diff options
Diffstat (limited to 'test/functional/ui')
33 files changed, 15576 insertions, 3814 deletions
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 46bfae8de2..81e514c9aa 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -303,7 +303,7 @@ describe('Buffer highlighting', function() {1:~ }| {1:~ }| {1:~ }| - 2 change3; before #3 {MATCH:.*}| + 2 changes; before #3 {MATCH:.*}| ]]} command('undo') @@ -751,8 +751,8 @@ describe('Buffer highlighting', function() it('validates contents', function() -- this used to leak memory - eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) - eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) + eq("Invalid 'chunk': expected Array, got String", pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) + eq("Invalid 'chunk': expected Array, got String", pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) end) it('can be retrieved', function() @@ -762,10 +762,9 @@ describe('Buffer highlighting', function() local s1 = {{'Köttbullar', 'Comment'}, {'Kräuterbutter'}} local s2 = {{'こんにちは', 'Comment'}} - -- 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, { + ns_id = 1, priority = 0, virt_text = s1, -- other details @@ -774,10 +773,10 @@ describe('Buffer highlighting', function() virt_text_hide = false, }}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true})) - -- TODO: is this really valid? shouldn't the max be line_count()-1? local lastline = line_count() set_virtual_text(id1, line_count(), s2, {}) eq({{3, lastline, 0, { + ns_id = 1, priority = 0, virt_text = s2, -- other details diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua index eb5de693bd..e4766103c2 100644 --- a/test/functional/ui/cmdline_highlight_spec.lua +++ b/test/functional/ui/cmdline_highlight_spec.lua @@ -7,6 +7,7 @@ local clear = helpers.clear local meths = helpers.meths local funcs = helpers.funcs local source = helpers.source +local exec_capture = helpers.exec_capture local dedent = helpers.dedent local command = helpers.command local curbufmeths = helpers.curbufmeths @@ -177,7 +178,7 @@ end describe('Command-line coloring', function() it('works', function() set_color_cb('RainBowParens') - meths.set_option('more', false) + meths.set_option_value('more', false, {}) start_prompt() screen:expect([[ | @@ -362,7 +363,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec('messages', true)) + eq('', exec_capture('messages')) end) it('silences :echon', function() set_color_cb('Echoning') @@ -377,7 +378,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec('messages', true)) + eq('', exec_capture('messages')) end) it('silences :echomsg', function() set_color_cb('Echomsging') @@ -392,7 +393,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec('messages', true)) + eq('', exec_capture('messages')) end) it('does the right thing when throwing', function() set_color_cb('Throwing') @@ -576,10 +577,10 @@ describe('Command-line coloring', function() | {EOB:~ }| {EOB:~ }| + {EOB:~ }| {MSEP: }| :+ | {ERR:E5404: Chunk 1 end 3 not in range (1, 2]}| - | :++^ | ]]) end) @@ -853,12 +854,12 @@ describe('Ex commands coloring', function() :# | {ERR:Error detected while processing :} | {ERR:E605: Exception not caught: 42} | - {ERR:E749: empty buffer} | + {ERR:E749: Empty buffer} | {PE:Press ENTER or type command to continue}^ | ]]) feed('<CR>') - eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer', - meths.exec('messages', true)) + eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: Empty buffer', + exec_capture('messages')) end) it('errors out when failing to get callback', function() meths.set_var('Nvim_color_cmdline', 42) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 1c9ac7f7ba..188b9ee87b 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -24,6 +24,7 @@ local function new_screen(opt) [7] = {bold = true, foreground = Screen.colors.Brown}, [8] = {background = Screen.colors.LightGrey}, [9] = {bold = true}, + [10] = {background = Screen.colors.Yellow1}; }) return screen end @@ -316,7 +317,7 @@ local function test_cmdline(linegrid) screen:expect{grid=[[ | {2:[No Name] }| - {1::}make^ | + {1::}mak^e | {3:[Command Line] }| | ]]} @@ -326,7 +327,7 @@ local function test_cmdline(linegrid) screen:expect{grid=[[ | {2:[No Name] }| - {1::}make^ | + {1::}mak^e | {3:[Command Line] }| | ]], cmdline={nil, { @@ -339,7 +340,7 @@ local function test_cmdline(linegrid) screen:expect{grid=[[ | {2:[No Name] }| - {1::}make^ | + {1::}mak^e | {3:[Command Line] }| | ]], cmdline={nil, { @@ -352,7 +353,7 @@ local function test_cmdline(linegrid) screen:expect{grid=[[ | {2:[No Name] }| - {1::}make^ | + {1::}mak^e | {3:[Command Line] }| | ]]} @@ -771,6 +772,84 @@ describe('cmdline redraw', function() :^abc | ]]) end) + + it('with rightleftcmd', function() + command('set rightleft rightleftcmd=search shortmess+=s') + meths.buf_set_lines(0, 0, -1, true, {"let's rock!"}) + screen:expect{grid=[[ + !kcor s'te^l| + {1: ~}| + {1: ~}| + {1: ~}| + | + ]]} + + feed '/' + screen:expect{grid=[[ + !kcor s'tel| + {1: ~}| + {1: ~}| + {1: ~}| + ^ /| + ]]} + + feed "let's" + -- note: cursor looks off but looks alright in real use + -- when rendered as a block so it touches the end of the text + screen:expect{grid=[[ + !kcor {2:s'tel}| + {1: ~}| + {1: ~}| + {1: ~}| + ^ s'tel/| + ]]} + + -- cursor movement + feed "<space>" + screen:expect{grid=[[ + !kcor{2: s'tel}| + {1: ~}| + {1: ~}| + {1: ~}| + ^ s'tel/| + ]]} + + feed "rock" + screen:expect{grid=[[ + !{2:kcor s'tel}| + {1: ~}| + {1: ~}| + {1: ~}| + ^ kcor s'tel/| + ]]} + + feed "<right>" + screen:expect{grid=[[ + !{2:kcor s'tel}| + {1: ~}| + {1: ~}| + {1: ~}| + ^kcor s'tel/| + ]]} + + feed "<left>" + screen:expect{grid=[[ + !{2:kcor s'tel}| + {1: ~}| + {1: ~}| + {1: ~}| + ^ kcor s'tel/| + ]]} + + feed "<cr>" + screen:expect{grid=[[ + !{10:kcor s'te^l}| + {1: ~}| + {1: ~}| + {1: ~}| + kcor s'tel/ | + ]]} + end) end) describe('statusline is redrawn on entering cmdline', function() @@ -944,15 +1023,64 @@ describe('statusline is redrawn on entering cmdline', function() end) end) +it('tabline is not redrawn in Ex mode #24122', function() + clear() + local screen = Screen.new(60, 5) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {bold = true, reverse = true}, -- MsgSeparator + [2] = {reverse = true}, -- TabLineFill + }) + screen:attach() + + exec([[ + set showtabline=2 + set tabline=%!MyTabLine() + + function! MyTabLine() + + return "foo" + endfunction + ]]) + + feed('gQ') + screen:expect{grid=[[ + {2:foo }| + | + {1: }| + Entering Ex mode. Type "visual" to go to Normal mode. | + :^ | + ]]} + + feed('echo 1<CR>') + screen:expect{grid=[[ + {1: }| + Entering Ex mode. Type "visual" to go to Normal mode. | + :echo 1 | + 1 | + :^ | + ]]} +end) + describe("cmdline height", function() + before_each(clear) + it("does not crash resized screen #14263", function() - clear() local screen = Screen.new(25, 10) screen:attach() command('set cmdheight=9999') screen:try_resize(25, 5) assert_alive() end) + + it('unchanged when restoring window sizes with global statusline', function() + command('set cmdheight=2 laststatus=2') + feed('q:') + command('set cmdheight=1 laststatus=3 | quit') + -- Available lines changed, so closing cmdwin should skip restoring window sizes, leaving the + -- cmdheight unchanged. + eq(1, eval('&cmdheight')) + end) end) describe('cmdheight=0', function() @@ -972,6 +1100,26 @@ describe('cmdheight=0', function() screen:attach() end) + it("with redrawdebug=invalid resize -1", function() + command("set redrawdebug=invalid cmdheight=0 noruler laststatus=0") + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + feed(":resize -1<CR>") + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + assert_alive() + end) + it("with cmdheight=1 noruler laststatus=2", function() command("set cmdheight=1 noruler laststatus=2") screen:expect{grid=[[ @@ -1226,6 +1374,7 @@ describe('cmdheight=0', function() it('with multigrid', function() clear{args={'--cmd', 'set cmdheight=0'}} screen:attach{ext_multigrid=true} + meths.buf_set_lines(0, 0, -1, true, {'p'}) screen:expect{grid=[[ ## grid 1 [2:-------------------------]| @@ -1234,14 +1383,14 @@ describe('cmdheight=0', function() [2:-------------------------]| [2:-------------------------]| ## grid 2 - ^ | + ^p | {1:~ }| {1:~ }| {1:~ }| {1:~ }| ## grid 3 ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} feed '/p' @@ -1253,7 +1402,7 @@ describe('cmdheight=0', function() [2:-------------------------]| [3:-------------------------]| ## grid 2 - | + {6:p} | {1:~ }| {1:~ }| {1:~ }| @@ -1261,7 +1410,7 @@ describe('cmdheight=0', function() ## grid 3 /p^ | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} end) @@ -1378,7 +1527,21 @@ describe('cmdheight=0', function() | ]]) command('set cmdheight=0') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] }| + ]]} command('resize -1') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {2:[No Name] }| + | + ]]} command('resize +1') screen:expect([[ ^ | diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index e261f0dfab..05057ca080 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -212,10 +212,10 @@ describe('ui/cursor', function() if m.blinkwait then m.blinkwait = 700 end end if m.hl_id then - m.hl_id = 60 + m.hl_id = 64 m.attr = {background = Screen.colors.DarkGray} end - if m.id_lm then m.id_lm = 62 end + if m.id_lm then m.id_lm = 67 end end -- Assert the new expectation. @@ -265,8 +265,8 @@ describe('ui/cursor', function() } -- Another cursor style. - meths.set_option('guicursor', 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173' - ..',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42') + meths.set_option_value('guicursor', 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173' + ..',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42', {}) screen:expect(function() local named = {} for _, m in ipairs(screen._mode_info) do @@ -288,7 +288,7 @@ describe('ui/cursor', function() end) -- If there is no setting for guicursor, it becomes the default setting. - meths.set_option('guicursor', 'n:ver35-blinkwait171-blinkoff172-blinkon173-Cursor/lCursor') + meths.set_option_value('guicursor', 'n:ver35-blinkwait171-blinkoff172-blinkon173-Cursor/lCursor', {}) screen:expect(function() for _,m in ipairs(screen._mode_info) do if m.name ~= 'normal' then @@ -304,7 +304,7 @@ describe('ui/cursor', function() end) it("empty 'guicursor' sets cursor_shape=block in all modes", function() - meths.set_option('guicursor', '') + meths.set_option_value('guicursor', '', {}) screen:expect(function() -- Empty 'guicursor' sets enabled=false. eq(false, screen._cursor_style_enabled) diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 489c33d8b1..e8fcfc46fc 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -8,7 +8,12 @@ local exec_lua = helpers.exec_lua local exec = helpers.exec local expect_events = helpers.expect_events local meths = helpers.meths +local funcs = helpers.funcs +local curbufmeths = helpers.curbufmeths local command = helpers.command +local eq = helpers.eq +local assert_alive = helpers.assert_alive +local pcall_err = helpers.pcall_err describe('decorations providers', function() local screen @@ -31,8 +36,10 @@ describe('decorations providers', function() [12] = {foreground = tonumber('0x990000')}; [13] = {background = Screen.colors.LightBlue}; [14] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue}; - [15] = {special = Screen.colors.Blue1, undercurl = true}, + [15] = {special = Screen.colors.Blue, undercurl = true}, [16] = {special = Screen.colors.Red, undercurl = true}, + [17] = {foreground = Screen.colors.Red}, + [18] = {bold = true, foreground = Screen.colors.SeaGreen}; } end) @@ -47,15 +54,15 @@ describe('decorations providers', function() local function setup_provider(code) return exec_lua ([[ - local a = vim.api - _G.ns1 = a.nvim_create_namespace "ns1" + local api = vim.api + _G.ns1 = api.nvim_create_namespace "ns1" ]] .. (code or [[ beamtrace = {} local function on_do(kind, ...) table.insert(beamtrace, {kind, ...}) end ]]) .. [[ - a.nvim_set_decoration_provider(_G.ns1, { + api.nvim_set_decoration_provider(_G.ns1, { on_start = on_do; on_buf = on_do; on_win = on_do; on_line = on_do; on_end = on_do; _on_spell_nav = on_do; @@ -75,10 +82,10 @@ describe('decorations providers', function() -- rather than append, which used to spin in an infinite loop allocating -- memory until nvim crashed/was killed. setup_provider([[ - local ns2 = a.nvim_create_namespace "ns2" - a.nvim_set_decoration_provider(ns2, {}) + local ns2 = api.nvim_create_namespace "ns2" + api.nvim_set_decoration_provider(ns2, {}) ]]) - helpers.assert_alive() + assert_alive() end) it('leave a trace', function() @@ -98,7 +105,7 @@ describe('decorations providers', function() ]]} check_trace { { "start", 4 }; - { "win", 1000, 1, 0, 8 }; + { "win", 1000, 1, 0, 6 }; { "line", 1000, 1, 0 }; { "line", 1000, 1, 1 }; { "line", 1000, 1, 2 }; @@ -122,8 +129,8 @@ describe('decorations providers', function() ]]} check_trace { { "start", 5 }; - { "buf", 1 }; - { "win", 1000, 1, 0, 8 }; + { "buf", 1, 5 }; + { "win", 1000, 1, 0, 6 }; { "line", 1000, 1, 6 }; { "end", 5 }; } @@ -132,12 +139,12 @@ describe('decorations providers', function() it('can have single provider', function() insert(mulholland) setup_provider [[ - local hl = a.nvim_get_hl_id_by_name "ErrorMsg" - local test_ns = a.nvim_create_namespace "mulholland" + local hl = api.nvim_get_hl_id_by_name "ErrorMsg" + local test_ns = api.nvim_create_namespace "mulholland" function on_do(event, ...) if event == "line" then local win, buf, line = ... - a.nvim_buf_set_extmark(buf, test_ns, line, line, + api.nvim_buf_set_extmark(buf, test_ns, line, line, { end_line = line, end_col = line+1, hl_group = hl, ephemeral = true @@ -172,11 +179,11 @@ describe('decorations providers', function() ]] setup_provider [[ - local ns = a.nvim_create_namespace "spell" + local ns = api.nvim_create_namespace "spell" beamtrace = {} local function on_do(kind, ...) if kind == 'win' or kind == 'spell' then - a.nvim_buf_set_extmark(0, ns, 0, 0, { + api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, end_col = 23, spell = true, @@ -190,7 +197,7 @@ describe('decorations providers', function() check_trace { { "start", 5 }; - { "win", 1000, 1, 0, 5 }; + { "win", 1000, 1, 0, 3 }; { "line", 1000, 1, 0 }; { "line", 1000, 1, 1 }; { "line", 1000, 1, 2 }; @@ -201,14 +208,14 @@ describe('decorations providers', function() feed "gg0" screen:expect{grid=[[ - ^I am well written text. | - {15:i} am not capitalized. | - I am a {16:speling} {16:mistakke}. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + ^I am well written text. | + {15:i} am not capitalized. | + I am a {16:speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} feed "]s" @@ -216,14 +223,14 @@ describe('decorations providers', function() { "spell", 1000, 1, 1, 0, 1, -1 }; } screen:expect{grid=[[ - I am well written text. | - {15:^i} am not capitalized. | - I am a {16:speling} {16:mistakke}. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + I am well written text. | + {15:^i} am not capitalized. | + I am a {16:speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} feed "]s" @@ -231,43 +238,68 @@ describe('decorations providers', function() { "spell", 1000, 1, 2, 7, 2, -1 }; } screen:expect{grid=[[ - I am well written text. | - {15:i} am not capitalized. | - I am a {16:^speling} {16:mistakke}. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + I am well written text. | + {15:i} am not capitalized. | + I am a {16:^speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} - -- spell=false with lower priority doesn't disable spell + -- spell=false with higher priority does disable spell local ns = meths.create_namespace "spell" - local id = helpers.curbufmeths.set_extmark(ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false }) + local id = curbufmeths.set_extmark(ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false }) screen:expect{grid=[[ - I am well written text. | - i am not capitalized. | - I am a ^speling mistakke. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + I am well written text. | + i am not capitalized. | + I am a ^speling mistakke. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} - -- spell=false with higher priority does disable spell - helpers.curbufmeths.set_extmark(ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false }) + feed "]s" + screen:expect{grid=[[ + I am well written text. | + i am not capitalized. | + I am a ^speling mistakke. | + | + {1:~ }| + {1:~ }| + {1:~ }| + {17:search hit BOTTOM, continuing at TOP} | + ]]} + command('echo ""') + + -- spell=false with lower priority doesn't disable spell + curbufmeths.set_extmark(ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false }) screen:expect{grid=[[ - I am well written text. | - {15:i} am not capitalized. | - I am a {16:^speling} {16:mistakke}. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + I am well written text. | + {15:i} am not capitalized. | + I am a {16:^speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed "]s" + screen:expect{grid=[[ + I am well written text. | + {15:i} am not capitalized. | + I am a {16:speling} {16:^mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} end) @@ -330,12 +362,12 @@ describe('decorations providers', function() ]]} exec_lua [[ - local a = vim.api - local thewin = a.nvim_get_current_win() - local ns2 = a.nvim_create_namespace 'ns2' - a.nvim_set_decoration_provider (ns2, { + local api = vim.api + local thewin = api.nvim_get_current_win() + local ns2 = api.nvim_create_namespace 'ns2' + api.nvim_set_decoration_provider (ns2, { on_win = function (_, win, buf) - a.nvim_set_hl_ns_fast(win == thewin and _G.ns1 or ns2) + api.nvim_set_hl_ns_fast(win == thewin and _G.ns1 or ns2) end; }) ]] @@ -436,12 +468,12 @@ describe('decorations providers', function() it('can have virtual text', function() insert(mulholland) setup_provider [[ - local hl = a.nvim_get_hl_id_by_name "ErrorMsg" - local test_ns = a.nvim_create_namespace "mulholland" + local hl = api.nvim_get_hl_id_by_name "ErrorMsg" + local test_ns = api.nvim_create_namespace "mulholland" function on_do(event, ...) if event == "line" then local win, buf, line = ... - a.nvim_buf_set_extmark(buf, test_ns, line, 0, { + api.nvim_buf_set_extmark(buf, test_ns, line, 0, { virt_text = {{'+', 'ErrorMsg'}}; virt_text_pos='overlay'; ephemeral = true; @@ -465,12 +497,12 @@ describe('decorations providers', function() it('can have virtual text of the style: right_align', function() insert(mulholland) setup_provider [[ - local hl = a.nvim_get_hl_id_by_name "ErrorMsg" - local test_ns = a.nvim_create_namespace "mulholland" + local hl = api.nvim_get_hl_id_by_name "ErrorMsg" + local test_ns = api.nvim_create_namespace "mulholland" function on_do(event, ...) if event == "line" then local win, buf, line = ... - a.nvim_buf_set_extmark(buf, test_ns, line, 0, { + api.nvim_buf_set_extmark(buf, test_ns, line, 0, { virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}}; virt_text_pos='right_align'; ephemeral = true; @@ -491,15 +523,81 @@ describe('decorations providers', function() ]]} end) + it('virtual text works with wrapped lines', function() + insert(mulholland) + feed('ggJj3JjJ') + setup_provider [[ + local hl = api.nvim_get_hl_id_by_name "ErrorMsg" + local test_ns = api.nvim_create_namespace "mulholland" + function on_do(event, ...) + if event == "line" then + local win, buf, line = ... + api.nvim_buf_set_extmark(buf, test_ns, line, 0, { + virt_text = {{string.rep('/', line+1), 'ErrorMsg'}}; + virt_text_pos='eol'; + ephemeral = true; + }) + api.nvim_buf_set_extmark(buf, test_ns, line, 6, { + virt_text = {{string.rep('*', line+1), 'ErrorMsg'}}; + virt_text_pos='overlay'; + ephemeral = true; + }) + api.nvim_buf_set_extmark(buf, test_ns, line, 39, { + virt_text = {{string.rep('!', line+1), 'ErrorMsg'}}; + virt_text_win_col=20; + ephemeral = true; + }) + api.nvim_buf_set_extmark(buf, test_ns, line, 40, { + virt_text = {{string.rep('?', line+1), 'ErrorMsg'}}; + virt_text_win_col=10; + ephemeral = true; + }) + api.nvim_buf_set_extmark(buf, test_ns, line, 40, { + virt_text = {{string.rep(';', line+1), 'ErrorMsg'}}; + virt_text_pos='overlay'; + ephemeral = true; + }) + api.nvim_buf_set_extmark(buf, test_ns, line, 40, { + virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}}; + virt_text_pos='right_align'; + ephemeral = true; + }) + end + end + ]] + + screen:expect{grid=[[ + // jus{2:*} to see if th{2:!}re was an accident | + {2:;}n Mulholl{2:?}nd Drive {2:/} +{2: }| + try_st{2:**}t(); bufref_{2:!!}save_buf; switch_b| + {2:;;}fer(&sav{2:??}buf, buf); {2://} +{2: }| + posp ={2:***}tmark(mark,{2:!!!}lse);^ restore_buf| + {2:;;;}(&save_{2:???}); {2:///} +{2: }| + {1:~ }| + | + ]]} + command('setlocal breakindent breakindentopt=shift:2') + screen:expect{grid=[[ + // jus{2:*} to see if th{2:!}re was an accident | + {2:;}n Mulho{2:?}land Drive {2:/} +{2: }| + try_st{2:**}t(); bufref_{2:!!}save_buf; switch_b| + {2:;;}fer(&s{2:??}e_buf, buf); {2://} +{2: }| + posp ={2:***}tmark(mark,{2:!!!}lse);^ restore_buf| + {2:;;;}(&sav{2:???}uf); {2:///} +{2: }| + {1:~ }| + | + ]]} + end) + it('can highlight beyond EOL', function() insert(mulholland) setup_provider [[ - local test_ns = a.nvim_create_namespace "veberod" + local test_ns = api.nvim_create_namespace "veberod" function on_do(event, ...) if event == "line" then local win, buf, line = ... - if string.find(a.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then - a.nvim_buf_set_extmark(buf, test_ns, line, 0, { + if string.find(api.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then + api.nvim_buf_set_extmark(buf, test_ns, line, 0, { end_line = line+1; hl_group = 'DiffAdd'; hl_eol = true; @@ -534,9 +632,9 @@ describe('decorations providers', function() local function on_do(kind, winid, bufnr, topline, botline_guess) if kind == 'win' then if topline < 100 and botline_guess > 100 then - vim.api.nvim_buf_set_extmark(bufnr, ns1, 99, -1, { sign_text = 'X' }) + api.nvim_buf_set_extmark(bufnr, ns1, 99, -1, { sign_text = 'X' }) else - vim.api.nvim_buf_clear_namespace(bufnr, ns1, 0, -1) + api.nvim_buf_clear_namespace(bufnr, ns1, 0, -1) end end end @@ -565,8 +663,60 @@ describe('decorations providers', function() | ]]) end) + + it('does allow removing extmarks during on_line callbacks', function() + exec_lua([[ + eok = true + ]]) + setup_provider([[ + local function on_do(kind, winid, bufnr, topline, botline_guess) + if kind == 'line' then + api.nvim_buf_set_extmark(bufnr, ns1, 1, -1, { sign_text = 'X' }) + eok = pcall(api.nvim_buf_clear_namespace, bufnr, ns1, 0, -1) + end + end + ]]) + exec_lua([[ + assert(eok == true) + ]]) + end) + + it('errors gracefully', function() + insert(mulholland) + + setup_provider [[ + function on_do(...) + error "Foo" + end + ]] + + screen:expect{grid=[[ + {2:Error in decoration provider ns1.start:} | + {2:Error executing lua: [string "<nvim>"]:4}| + {2:: Foo} | + {2:stack traceback:} | + {2: [C]: in function 'error'} | + {2: [string "<nvim>"]:4: in function}| + {2: <[string "<nvim>"]:3>} | + {18:Press ENTER or type command to continue}^ | + ]]} + end) end) +local example_text = [[ +for _,item in ipairs(items) do + local text, hl_id_cell, count = unpack(item) + if hl_id_cell ~= nil then + hl_id = hl_id_cell + end + for _ = 1, (count or 1) do + local cell = line[colpos] + cell.text = text + cell.hl_id = hl_id + colpos = colpos+1 + end +end]] + describe('extmark decorations', function() local screen, ns before_each( function() @@ -592,7 +742,7 @@ describe('extmark decorations', function() [16] = {blend = 30, background = Screen.colors.Red1, foreground = Screen.colors.Magenta1}; [17] = {bold = true, foreground = Screen.colors.Brown, background = Screen.colors.LightGrey}; [18] = {background = Screen.colors.LightGrey}; - [19] = {foreground = Screen.colors.Cyan4, background = Screen.colors.LightGrey}; + [19] = {foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGrey}; [20] = {foreground = tonumber('0x180606'), background = tonumber('0xf13f3f')}; [21] = {foreground = Screen.colors.Gray0, background = tonumber('0xf13f3f')}; [22] = {foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f')}; @@ -601,25 +751,25 @@ describe('extmark decorations', function() [25] = {background = Screen.colors.LightRed}; [26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey}; [27] = {background = Screen.colors.Plum1}; + [28] = {underline = true, foreground = Screen.colors.SlateBlue}; + [29] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightGray, underline = true}; + [30] = {foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGray, underline = true}; + [31] = {underline = true, foreground = Screen.colors.DarkCyan}; + [32] = {underline = true}; + [33] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray}; + [34] = {background = Screen.colors.Yellow}; + [35] = {background = Screen.colors.Yellow, bold = true, foreground = Screen.colors.Blue}; + [36] = {foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.Red}; + [37] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue}; + [38] = {background = Screen.colors.LightBlue}; + [39] = {foreground = Screen.colors.Blue1, background = Screen.colors.LightCyan1, bold = true}; + [40] = {reverse = true}; + [41] = {bold = true, reverse = true}; } ns = meths.create_namespace 'test' end) - local example_text = [[ -for _,item in ipairs(items) do - local text, hl_id_cell, count = unpack(item) - if hl_id_cell ~= nil then - hl_id = hl_id_cell - end - for _ = 1, (count or 1) do - local cell = line[colpos] - cell.text = text - cell.hl_id = hl_id - colpos = colpos+1 - end -end]] - it('empty virtual text at eol should not break colorcolumn #17860', function() insert(example_text) feed('gg') @@ -660,14 +810,14 @@ end]] -- can "float" beyond end of line meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'}) -- bound check: right edge of window - meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork '}, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'}) + meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork'}, {(' bork'):rep(10), 'ErrorMsg'}}, virt_text_pos='overlay'}) -- empty virt_text should not change anything meths.buf_set_extmark(0, ns, 6, 16, { virt_text={{''}}, virt_text_pos='overlay'}) screen:expect{grid=[[ ^for _,item in ipairs(items) do | {2:|} local text, hl_id_cell, count = unpack(item) | - {2:|} if hl_id_cell ~= nil tbork bork bork {4:bork bork}| + {2:|} if hl_id_cell ~= nil tbork bork bork{4: bork bork}| {2:|} {1:|} hl_id = hl_id_cell | {2:|} end | {2:|} for _ = 1, (count or 1) {4:loopy} | @@ -682,7 +832,6 @@ end]] | ]]} - -- handles broken lines screen:try_resize(22, 25) screen:expect{grid=[[ @@ -692,7 +841,7 @@ end]] cell, count = unpack(i| tem) | {2:|} if hl_id_cell ~= n| - il tbork bork bork {4:bor}| + il tbork bork bork{4: bor}| {2:|} {1:|} hl_id = hl_id_| cell | {2:|} end | @@ -712,6 +861,248 @@ end]] {1:~ }| | ]]} + + -- truncating in the middle of a char leaves a space + meths.buf_set_lines(0, 0, 1, true, {'for _,item in ipairs(items) do -- 古古古'}) + meths.buf_set_lines(0, 10, 12, true, {' end -- ??????????', 'end -- ?古古古古?古古'}) + meths.buf_set_extmark(0, ns, 0, 35, { virt_text={{'A', 'ErrorMsg'}, {'AA'}}, virt_text_pos='overlay'}) + meths.buf_set_extmark(0, ns, 10, 19, { virt_text={{'口口口', 'ErrorMsg'}}, virt_text_pos='overlay'}) + meths.buf_set_extmark(0, ns, 11, 21, { virt_text={{'口口口', 'ErrorMsg'}}, virt_text_pos='overlay'}) + meths.buf_set_extmark(0, ns, 11, 8, { virt_text={{'口口', 'ErrorMsg'}}, virt_text_pos='overlay'}) + screen:expect{grid=[[ + ^for _,item in ipairs(i| + tems) do -- {4:A}AA 古 | + {2:|} local text, hl_id_| + cell, count = unpack(i| + tem) | + {2:|} if hl_id_cell ~= n| + il tbork bork bork{4: bor}| + {2:|} {1:|} hl_id = hl_id_| + cell | + {2:|} end | + {2:|} for _ = 1, (count | + or 1) {4:loopy} | + {2:|} {1:|} local cell = l| + ine[colpos] | + {2:|} {1:|} cell.text = te| + xt | + {2:|} {1:|} cell.hl_id = h| + l_id | + {2:|} {1:|} cofoo{3:bar}{4:!!}olpo| + s+1 | + end -- ???????{4:口 }| + end -- {4:口口} 古古{4:口口 }| + {1:~ }| + {1:~ }| + | + ]]} + + screen:try_resize(82, 13) + screen:expect{grid=[[ + ^for _,item in ipairs(items) do -- {4:A}AA 古 | + {2:|} local text, hl_id_cell, count = unpack(item) | + {2:|} if hl_id_cell ~= nil tbork bork bork{4: bork bork bork bork bork bork bork bork b}| + {2:|} {1:|} hl_id = hl_id_cell | + {2:|} end | + {2:|} for _ = 1, (count or 1) {4:loopy} | + {2:|} {1:|} local cell = line[colpos] | + {2:|} {1:|} cell.text = text | + {2:|} {1:|} cell.hl_id = hl_id | + {2:|} {1:|} cofoo{3:bar}{4:!!}olpos+1 | + end -- ???????{4:口口口} | + end -- {4:口口} 古古{4:口口口} | + | + ]]} + + meths.buf_clear_namespace(0, ns, 0, -1) + screen:expect{grid=[[ + ^for _,item in ipairs(items) do -- 古古古 | + local text, hl_id_cell, count = unpack(item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + cell.hl_id = hl_id | + colpos = colpos+1 | + end -- ?????????? | + end -- ?古古古古?古古 | + | + ]]} + end) + + it('overlay virtual text works with wrapped lines #25158', function() + screen:try_resize(50, 6) + insert(('ab'):rep(100)) + for i = 0, 9 do + meths.buf_set_extmark(0, ns, 0, 42 + i, { virt_text={{tostring(i), 'ErrorMsg'}}, virt_text_pos='overlay'}) + meths.buf_set_extmark(0, ns, 0, 91 + i, { virt_text={{tostring(i), 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true}) + end + screen:expect{grid=[[ + ababababababababababababababababababababab{4:01234567}| + {4:89}abababababababababababababababababababa{4:012345678}| + {4:9}babababababababababababababababababababababababab| + ababababababababababababababababababababababababa^b| + {1:~ }| + | + ]]} + + command('set showbreak=++') + screen:expect{grid=[[ + ababababababababababababababababababababab{4:01234567}| + {1:++}{4:89}abababababababababababababababababababa{4:0123456}| + {1:++}{4:789}babababababababababababababababababababababab| + {1:++}abababababababababababababababababababababababab| + {1:++}ababa^b | + | + ]]} + + feed('2gkvg0') + screen:expect{grid=[[ + ababababababababababababababababababababab{4:01234567}| + {1:++}{4:89}abababababababababababababababababababa{4:0123456}| + {1:++}^a{18:babab}ababababababababababababababababababababab| + {1:++}abababababababababababababababababababababababab| + {1:++}ababab | + {24:-- VISUAL --} | + ]]} + + feed('o') + screen:expect{grid=[[ + ababababababababababababababababababababab{4:01234567}| + {1:++}{4:89}abababababababababababababababababababa{4:0123456}| + {1:++}{18:ababa}^bababababababababababababababababababababab| + {1:++}abababababababababababababababababababababababab| + {1:++}ababab | + {24:-- VISUAL --} | + ]]} + + feed('gk') + screen:expect{grid=[[ + ababababababababababababababababababababab{4:01234567}| + {1:++}{4:89}aba^b{18:ababababababababababababababababababababab}| + {1:++}{18:a}{4:89}babababababababababababababababababababababab| + {1:++}abababababababababababababababababababababababab| + {1:++}ababab | + {24:-- VISUAL --} | + ]]} + + feed('o') + screen:expect{grid=[[ + ababababababababababababababababababababab{4:01234567}| + {1:++}{4:89}aba{18:bababababababababababababababababababababab}| + {1:++}^a{4:89}babababababababababababababababababababababab| + {1:++}abababababababababababababababababababababababab| + {1:++}ababab | + {24:-- VISUAL --} | + ]]} + + feed('<Esc>$') + command('set number showbreak=') + screen:expect{grid=[[ + {2: 1 }ababababababababababababababababababababab{4:0123}| + {2: }{4:456789}abababababababababababababababababababa{4:0}| + {2: }{4:123456789}babababababababababababababababababab| + {2: }ababababababababababababababababababababababab| + {2: }abababababababa^b | + | + ]]} + + command('set cpoptions+=n') + screen:expect{grid=[[ + {2: 1 }ababababababababababababababababababababab{4:0123}| + {4:456789}abababababababababababababababababababa{4:01234}| + {4:56789}babababababababababababababababababababababab| + ababababababababababababababababababababababababab| + aba^b | + | + ]]} + + feed('0g$hi<Tab>') + screen:expect{grid=[[ + {2: 1 }ababababababababababababababababababababab{4:01} | + {4:^23456789}abababababababababababababababababababa{4:0}| + {4:123456789}babababababababababababababababababababab| + ababababababababababababababababababababababababab| + abababab | + {24:-- INSERT --} | + ]]} + end) + + it('virt_text_hide hides overlay virtual text when extmark is off-screen', function() + screen:try_resize(50, 3) + command('set nowrap') + meths.buf_set_lines(0, 0, -1, true, {'-- ' .. ('…'):rep(57)}) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text={{'?????', 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true}) + meths.buf_set_extmark(0, ns, 0, 123, { virt_text={{'!!!!!', 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true}) + screen:expect{grid=[[ + {4:^?????}……………………………………………………………………………………………………{4:!!!!!}……| + {1:~ }| + | + ]]} + feed('40zl') + screen:expect{grid=[[ + ^………{4:!!!!!}……………………………… | + {1:~ }| + | + ]]} + feed('3zl') + screen:expect{grid=[[ + {4:^!!!!!}……………………………… | + {1:~ }| + | + ]]} + feed('7zl') + screen:expect{grid=[[ + ^………………………… | + {1:~ }| + | + ]]} + + command('set wrap smoothscroll') + screen:expect{grid=[[ + {4:?????}……………………………………………………………………………………………………{4:!!!!!}……| + ^………………………… | + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:<<<}………………^… | + {1:~ }| + | + ]]} + screen:try_resize(40, 3) + screen:expect{grid=[[ + {1:<<<}{4:!!!!!}……………………………^… | + {1:~ }| + | + ]]} + feed('<C-Y>') + screen:expect{grid=[[ + {4:?????}……………………………………………………………………………………………| + ………{4:!!!!!}……………………………^… | + | + ]]} + end) + + it('overlay virtual text works on and after a TAB #24022', function() + screen:try_resize(40, 3) + meths.buf_set_lines(0, 0, -1, true, {'\t\tline 1'}) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'AA', 'Search'}}, virt_text_pos = 'overlay', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 0, 1, { virt_text = {{'BB', 'Search'}}, virt_text_pos = 'overlay', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'CC', 'Search'}}, virt_text_pos = 'overlay', hl_mode = 'combine' }) + screen:expect{grid=[[ + {34:AA} ^ {34:BB} {34:CC}ne 1 | + {1:~ }| + | + ]]} + command('setlocal list listchars=tab:<->') + screen:expect{grid=[[ + {35:^AA}{1:----->}{35:BB}{1:----->}{34:CC}ne 1 | + {1:~ }| + | + ]]} end) it('can have virtual text of overlay position and styling', function() @@ -805,25 +1196,30 @@ end]] ]]} end) - it('can have virtual text of fixed win_col position', function() + it('can have virtual text of right_align and fixed win_col position', function() insert(example_text) feed 'gg' - meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) - meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) - meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'VERY', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'MUCH', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 3, 14, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 3, 14, { virt_text={{'ERROR', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'}) meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_pos='right_align', hl_mode='blend'}) -- empty virt_text should not change anything meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_win_col=14, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_pos='right_align', hl_mode='blend'}) screen:expect{grid=[[ ^for _,item in ipairs(items) do | - local text, hl_id_cell, cou{4:Very} unpack(item) | - if hl_id_cell ~= nil then {4:Much} | - hl_id = hl_id_cell {4:Error} | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if hl_id_cell ~= nil then {4:Much} {4:MUCH}| + hl_id = hl_id_cell {4:Error} {4:ERROR}| end | for _ = 1, (count or 1) do | local cell = line[colpos] | - {1:-} cell.text = text | + {1:-} cell.text = text {1:-}| cell.hl_id = hl_id | colpos = colpos+1 | end | @@ -836,14 +1232,14 @@ end]] feed '3G12|i<cr><esc>' screen:expect{grid=[[ for _,item in ipairs(items) do | - local text, hl_id_cell, cou{4:Very} unpack(item) | - if hl_i {4:Much} | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if hl_i {4:Much} {4:MUCH}| ^d_cell ~= nil then | - hl_id = hl_id_cell {4:Error} | + hl_id = hl_id_cell {4:Error} {4:ERROR}| end | for _ = 1, (count or 1) do | local cell = line[colpos] | - {1:-} cell.text = text | + {1:-} cell.text = text {1:-}| cell.hl_id = hl_id | colpos = colpos+1 | end | @@ -855,13 +1251,13 @@ end]] feed 'u:<cr>' screen:expect{grid=[[ for _,item in ipairs(items) do | - local text, hl_id_cell, cou{4:Very} unpack(item) | - if hl_i^d_cell ~= nil then {4:Much} | - hl_id = hl_id_cell {4:Error} | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if hl_i^d_cell ~= nil then {4:Much} {4:MUCH}| + hl_id = hl_id_cell {4:Error} {4:ERROR}| end | for _ = 1, (count or 1) do | local cell = line[colpos] | - {1:-} cell.text = text | + {1:-} cell.text = text {1:-}| cell.hl_id = hl_id | colpos = colpos+1 | end | @@ -874,14 +1270,14 @@ end]] feed '8|i<cr><esc>' screen:expect{grid=[[ for _,item in ipairs(items) do | - local text, hl_id_cell, cou{4:Very} unpack(item) | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| if | - ^hl_id_cell ~= nil then {4:Much} | - hl_id = hl_id_cell {4:Error} | + ^hl_id_cell ~= nil then {4:Much} {4:MUCH}| + hl_id = hl_id_cell {4:Error} {4:ERROR}| end | for _ = 1, (count or 1) do | local cell = line[colpos] | - {1:-} cell.text = text | + {1:-} cell.text = text {1:-}| cell.hl_id = hl_id | colpos = colpos+1 | end | @@ -889,9 +1285,273 @@ end]] {1:~ }| | ]]} + + feed 'jI-- <esc>..........' + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if | + hl_id_cell ~= nil then {4:Much} {4:MUCH}| + --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}| + l_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text {1:-}| + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + | + ]]} + + meths.buf_set_extmark(0, ns, 4, 50, { virt_text={{'EOL', 'NonText'}} }) + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if | + hl_id_cell ~= nil then {4:Much} {4:MUCH}| + --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}| + l_id_cell {1:EOL} | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text {1:-}| + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + | + ]]} + + feed '.' + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if | + hl_id_cell ~= nil then {4:Much} {4:MUCH}| + --^ -- -- -- -- -- -- -- -- -- -- -- hl_id | + = hl_id_cell {1:EOL} {4:Error} {4:ERROR}| + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text {1:-}| + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + | + ]]} + + command 'set number' + screen:expect{grid=[[ + {2: 1 }for _,item in ipairs(items) do | + {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}| + {2: }m) | + {2: 3 } if | + {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}| + {2: 5 } --^ -- -- -- -- -- -- -- -- -- -- -- hl| + {2: }_id = hl_id_cell {1:EOL} {4:Error} {4:ERROR}| + {2: 6 } end | + {2: 7 } for _ = 1, (count or 1) do | + {2: 8 } local cell = line[colpos] | + {2: 9 } {1:-} cell.text = text {1:-}| + {2: 10 } cell.hl_id = hl_id | + {2: 11 } colpos = colpos+1 | + {2: 12 } end | + | + ]]} + + command 'set cpoptions+=n' + screen:expect{grid=[[ + {2: 1 }for _,item in ipairs(items) do | + {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}| + m) | + {2: 3 } if | + {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}| + {2: 5 } --^ -- -- -- -- -- -- -- -- -- -- -- hl| + _id = hl_id_cell {1:EOL} {4:Error} {4:ERROR}| + {2: 6 } end | + {2: 7 } for _ = 1, (count or 1) do | + {2: 8 } local cell = line[colpos] | + {2: 9 } {1:-} cell.text = text {1:-}| + {2: 10 } cell.hl_id = hl_id | + {2: 11 } colpos = colpos+1 | + {2: 12 } end | + | + ]]} + + command 'set cpoptions-=n nowrap' + screen:expect{grid=[[ + {2: 1 }for _,item in ipairs(items) do | + {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}| + {2: 3 } if | + {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}| + {2: 5 } --^ -- -- -- -- -- -- --{4:Error}- -- {4:ERROR}| + {2: 6 } end | + {2: 7 } for _ = 1, (count or 1) do | + {2: 8 } local cell = line[colpos] | + {2: 9 } {1:-} cell.text = text {1:-}| + {2: 10 } cell.hl_id = hl_id | + {2: 11 } colpos = colpos+1 | + {2: 12 } end | + {2: 13 }end | + {1:~ }| + | + ]]} + + feed '12zl' + screen:expect{grid=[[ + {2: 1 }n ipairs(items) do | + {2: 2 }xt, hl_id_cell, count = unpack({4:Very}) {4:VERY}| + {2: 3 } | + {2: 4 }= nil then {4:Much} {4:MUCH}| + {2: 5 }^- -- -- -- -- -- -- -- -- -- --{4:Error}d = h{4:ERROR}| + {2: 6 } | + {2: 7 }1, (count or 1) do | + {2: 8 }l cell = line[colpos] | + {2: 9 }.tex{1:-} = text {1:-}| + {2: 10 }.hl_id = hl_id | + {2: 11 }os = colpos+1 | + {2: 12 } | + {2: 13 } | + {1:~ }| + | + ]]} + + feed('fhi<Tab>') + screen:expect{grid=[[ + {2: 1 }n ipairs(items) do | + {2: 2 }xt, hl_id_cell, count = unpack({4:Very}) {4:VERY}| + {2: 3 } | + {2: 4 }= nil then {4:Much} {4:MUCH}| + {2: 5 }- -- -- -- -- -- -- -- -- -- --{4:Error}^hl_id{4:ERROR}| + {2: 6 } | + {2: 7 }1, (count or 1) do | + {2: 8 }l cell = line[colpos] | + {2: 9 }.tex{1:-} = text {1:-}| + {2: 10 }.hl_id = hl_id | + {2: 11 }os = colpos+1 | + {2: 12 } | + {2: 13 } | + {1:~ }| + {24:-- INSERT --} | + ]]} + + feed('<Esc>0') + screen:expect{grid=[[ + {2: 1 }for _,item in ipairs(items) do | + {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}| + {2: 3 } if | + {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}| + {2: 5 }^ -- -- -- -- -- -- -- --{4:Error}- -- {4:ERROR}| + {2: 6 } end | + {2: 7 } for _ = 1, (count or 1) do | + {2: 8 } local cell = line[colpos] | + {2: 9 } {1:-} cell.text = text {1:-}| + {2: 10 } cell.hl_id = hl_id | + {2: 11 } colpos = colpos+1 | + {2: 12 } end | + {2: 13 }end | + {1:~ }| + | + ]]} + end) + + it('virtual text win_col out of window does not break display #25645', function() + screen:try_resize(51, 6) + command('vnew') + meths.buf_set_lines(0, 0, -1, false, { string.rep('a', 50) }) + screen:expect{grid=[[ + ^aaaaaaaaaaaaaaaaaaaaaaaaa│ | + aaaaaaaaaaaaaaaaaaaaaaaaa│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {41:[No Name] [+] }{40:[No Name] }| + | + ]]} + local extmark_opts = { virt_text_win_col = 35, virt_text = { { ' ', 'Comment' } } } + meths.buf_set_extmark(0, ns, 0, 0, extmark_opts) + screen:expect_unchanged() + assert_alive() + end) + + it('can have virtual text on folded line', function() + insert([[ + 11111 + 22222 + 33333]]) + command('1,2fold') + screen:try_resize(50, 3) + feed('zb') + -- XXX: the behavior of overlay virtual text at non-zero column is strange: + -- 1. With 'wrap' it is never shown. + -- 2. With 'nowrap' it is shown only if the extmark is hidden before leftcol. + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'AA', 'Underlined'}}, hl_mode = 'combine', virt_text_pos = 'overlay' }) + meths.buf_set_extmark(0, ns, 0, 5, { virt_text = {{'BB', 'Underlined'}}, hl_mode = 'combine', virt_text_win_col = 10 }) + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'CC', 'Underlined'}}, hl_mode = 'combine', virt_text_pos = 'right_align' }) + screen:expect{grid=[[ + {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}| + 3333^3 | + | + ]]} + command('set nowrap') + screen:expect_unchanged() + feed('zl') + screen:expect{grid=[[ + {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}| + 333^3 | + | + ]]} + feed('zl') + screen:expect{grid=[[ + {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}| + 33^3 | + | + ]]} + feed('zl') + screen:expect{grid=[[ + {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}| + 3^3 | + | + ]]} + end) + + it('virtual text works below diff filler lines', function() + screen:try_resize(53, 8) + insert([[ + aaaaa + bbbbb + ccccc + ddddd + eeeee]]) + command('rightbelow vnew') + insert([[ + bbbbb + ccccc + ddddd + eeeee]]) + command('windo diffthis') + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'AA', 'Underlined'}}, virt_text_pos = 'overlay' }) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'BB', 'Underlined'}}, virt_text_win_col = 10 }) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'CC', 'Underlined'}}, virt_text_pos = 'right_align' }) + screen:expect{grid=[[ + {37: }{38:aaaaa }│{37: }{39:------------------------}| + {37: }bbbbb │{37: }{28:AA}bbb {28:BB} {28:CC}| + {37: }ccccc │{37: }ccccc | + {37: }ddddd │{37: }ddddd | + {37: }eeeee │{37: }eeee^e | + {1:~ }│{1:~ }| + {40:[No Name] [+] }{41:[No Name] [+] }| + | + ]]} + command('windo set wrap') + screen:expect_unchanged() end) it('can have virtual text which combines foreground and background groups', function() + screen:try_resize(20, 5) + screen:set_default_attr_ids { [1] = {bold=true, foreground=Screen.colors.Blue}; [2] = {background = tonumber('0x123456'), foreground = tonumber('0xbbbbbb')}; @@ -909,30 +1569,24 @@ end]] hi VeryBold gui=bold ]] - meths.buf_set_extmark(0, ns, 0, 0, { virt_text={ + insert('##') + local vt = { {'a', {'BgOne', 'FgEin'}}; {'b', {'BgOne', 'FgZwei'}}; {'c', {'BgTwo', 'FgEin'}}; {'d', {'BgTwo', 'FgZwei'}}; {'X', {'BgTwo', 'FgZwei', 'VeryBold'}}; - }}) - + } + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'eol' }) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'right_align' }) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 0, { virt_lines = { vt, vt } }) screen:expect{grid=[[ - ^ {2:a}{3:b}{4:c}{5:d}{6:X} | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | + {2:a}{3:b}{4:c}{5:d}{6:X}#^# {2:a}{3:b}{4:c}{5:d}{6:X} {2:a}{3:b}{4:c}{5:d}{6:X}| + {2:a}{3:b}{4:c}{5:d}{6:X} | + {2:a}{3:b}{4:c}{5:d}{6:X} | + {1:~ }| + | ]]} end) @@ -980,21 +1634,94 @@ end]] {1:~ }| | ]]} - helpers.assert_alive() + assert_alive() end) - it('conceal #19007', function() + it('conceal with conceal char #19007', function() screen:try_resize(50, 5) insert('foo\n') - command('let &conceallevel=2') meths.buf_set_extmark(0, ns, 0, 0, {end_col=0, end_row=2, conceal='X'}) + command('set conceallevel=2') screen:expect([[ - {26:X} | - ^ | - {1:~ }| - {1:~ }| - | - ]]) + {26:X} | + ^ | + {1:~ }| + {1:~ }| + | + ]]) + command('set conceallevel=1') + screen:expect_unchanged() + + eq("conceal char has to be printable", pcall_err(meths.buf_set_extmark, 0, ns, 0, 0, {end_col=0, end_row=2, conceal='\255'})) + end) + + it('conceal with composed conceal char', function() + screen:try_resize(50, 5) + insert('foo\n') + meths.buf_set_extmark(0, ns, 0, 0, {end_col=0, end_row=2, conceal='ẍ̲'}) + command('set conceallevel=2') + screen:expect([[ + {26:ẍ̲} | + ^ | + {1:~ }| + {1:~ }| + | + ]]) + command('set conceallevel=1') + screen:expect_unchanged() + + -- this is rare, but could happen. Save at least the first codepoint + meths._invalidate_glyph_cache() + screen:expect{grid=[[ + {26:x} | + ^ | + {1:~ }| + {1:~ }| + | + ]]} + end) + + it('conceal without conceal char #24782', function() + screen:try_resize(50, 5) + insert('foobar\n') + meths.buf_set_extmark(0, ns, 0, 0, {end_col=3, conceal=''}) + command('set listchars=conceal:?') + command('let &conceallevel=1') + screen:expect([[ + {26:?}bar | + ^ | + {1:~ }| + {1:~ }| + | + ]]) + command('let &conceallevel=2') + screen:expect([[ + bar | + ^ | + {1:~ }| + {1:~ }| + | + ]]) + end) + + it('conceal works just before truncated double-width char #21486', function() + screen:try_resize(40, 4) + meths.buf_set_lines(0, 0, -1, true, {'', ('a'):rep(37) .. '<>古'}) + meths.buf_set_extmark(0, ns, 1, 37, {end_col=39, conceal=''}) + command('setlocal conceallevel=2') + screen:expect{grid=[[ + ^ | + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:>} | + 古 | + | + ]]} + feed('j') + screen:expect{grid=[[ + | + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<>{1:>}| + 古 | + | + ]]} end) it('avoids redraw issue #20651', function() @@ -1045,6 +1772,2005 @@ end]] end) + it('underline attribute with higher priority takes effect #22371', function() + screen:try_resize(50, 3) + insert('aaabbbaaa') + exec([[ + hi TestUL gui=underline guifg=Blue + hi TestUC gui=undercurl guisp=Red + hi TestBold gui=bold + ]]) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}; + [1] = {underline = true, foreground = Screen.colors.Blue}; + [2] = {undercurl = true, special = Screen.colors.Red}; + [3] = {underline = true, foreground = Screen.colors.Blue, special = Screen.colors.Red}; + [4] = {undercurl = true, foreground = Screen.colors.Blue, special = Screen.colors.Red}; + [5] = {bold = true, underline = true, foreground = Screen.colors.Blue}; + [6] = {bold = true, undercurl = true, special = Screen.colors.Red}; + }) + + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 20 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUC', priority = 30 }) + screen:expect([[ + {1:aaa}{4:bbb}{1:aa^a} | + {0:~ }| + | + ]]) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 20 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUL', priority = 30 }) + screen:expect([[ + {2:aaa}{3:bbb}{2:aa^a} | + {0:~ }| + | + ]]) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 30 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUC', priority = 20 }) + screen:expect([[ + {1:aaa}{3:bbb}{1:aa^a} | + {0:~ }| + | + ]]) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 30 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUL', priority = 20 }) + screen:expect([[ + {2:aaa}{4:bbb}{2:aa^a} | + {0:~ }| + | + ]]) + + -- When only one highlight group has an underline attribute, it should always take effect. + for _, d in ipairs({-5, 5}) do + meths.buf_clear_namespace(0, ns, 0, -1) + screen:expect([[ + aaabbbaa^a | + {0:~ }| + | + ]]) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 25 + d }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 25 - d }) + screen:expect([[ + {1:aaa}{5:bbb}{1:aa^a} | + {0:~ }| + | + ]]) + end + for _, d in ipairs({-5, 5}) do + meths.buf_clear_namespace(0, ns, 0, -1) + screen:expect([[ + aaabbbaa^a | + {0:~ }| + | + ]]) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 25 + d }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 25 - d }) + screen:expect([[ + {2:aaa}{6:bbb}{2:aa^a} | + {0:~ }| + | + ]]) + end + end) + + it('highlight is combined with syntax and sign linehl #20004', function() + screen:try_resize(50, 3) + insert([[ + function Func() + end]]) + feed('gg') + command('set ft=lua') + command('syntax on') + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 3, hl_mode = 'combine', hl_group = 'Visual' }) + command('hi default MyLine gui=underline') + command('sign define CurrentLine linehl=MyLine') + funcs.sign_place(6, 'Test', 'CurrentLine', '', { lnum = 1 }) + screen:expect{grid=[[ + {30:^fun}{31:ction}{32: Func() }| + {6:end} | + | + ]]} + end) + + it('highlight works after TAB with sidescroll #14201', function() + screen:try_resize(50, 3) + command('set nowrap') + meths.buf_set_lines(0, 0, -1, true, {'\tword word word word'}) + meths.buf_set_extmark(0, ns, 0, 1, { end_col = 3, hl_group = 'ErrorMsg' }) + screen:expect{grid=[[ + ^ {4:wo}rd word word word | + {1:~ }| + | + ]]} + feed('7zl') + screen:expect{grid=[[ + {4:^wo}rd word word word | + {1:~ }| + | + ]]} + feed('zl') + screen:expect{grid=[[ + {4:^wo}rd word word word | + {1:~ }| + | + ]]} + feed('zl') + screen:expect{grid=[[ + {4:^o}rd word word word | + {1:~ }| + | + ]]} + end) + + it('highlights the beginning of a TAB char correctly #23734', function() + screen:try_resize(50, 3) + meths.buf_set_lines(0, 0, -1, true, {'this is the\ttab'}) + meths.buf_set_extmark(0, ns, 0, 11, { end_col = 15, hl_group = 'ErrorMsg' }) + screen:expect{grid=[[ + ^this is the{4: tab} | + {1:~ }| + | + ]]} + + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 12, { end_col = 15, hl_group = 'ErrorMsg' }) + screen:expect{grid=[[ + ^this is the {4:tab} | + {1:~ }| + | + ]]} + end) + + it('highlight applies to a full TAB on line with matches #20885', function() + screen:try_resize(50, 3) + meths.buf_set_lines(0, 0, -1, true, {'\t-- match1', ' -- match2'}) + funcs.matchadd('Underlined', 'match') + meths.buf_set_extmark(0, ns, 0, 0, { end_row = 1, end_col = 0, hl_group = 'Visual' }) + meths.buf_set_extmark(0, ns, 1, 0, { end_row = 2, end_col = 0, hl_group = 'Visual' }) + screen:expect{grid=[[ + {18: ^ -- }{29:match}{18:1} | + {18: -- }{29:match}{18:2} | + | + ]]} + end) + + pending('highlight applies to a full TAB in visual block mode', function() + screen:try_resize(50, 8) + meths.buf_set_lines(0, 0, -1, true, {'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf'}) + meths.buf_set_extmark(0, ns, 0, 0, {end_row = 5, end_col = 0, hl_group = 'Underlined'}) + screen:expect([[ + {28:^asdf} | + {28: asdf} | + {28: asdf} | + {28: asdf} | + {28:asdf} | + {1:~ }| + {1:~ }| + | + ]]) + feed('<C-V>Gll') + screen:expect([[ + {29:asd}{28:f} | + {29: }{28: asdf} | + {29: }{28: asdf} | + {29: }{28: asdf} | + {29:as}{28:^df} | + {1:~ }| + {1:~ }| + {24:-- VISUAL BLOCK --} | + ]]) + end) + + it('supports multiline highlights', function() + insert(example_text) + feed 'gg' + for _,i in ipairs {1,2,3,5,6,7} do + for _,j in ipairs {2,5,10,15} do + meths.buf_set_extmark(0, ns, i, j, { end_col=j+2, hl_group = 'NonText'}) + end + end + screen:expect{grid=[[ + ^for _,item in ipairs(items) do | + {1: }l{1:oc}al {1:te}xt,{1: h}l_id_cell, count = unpack(item) | + {1: }i{1:f }hl_{1:id}_ce{1:ll} ~= nil then | + {1: } {1: } hl{1:_i}d ={1: h}l_id_cell | + end | + {1: }f{1:or} _ {1:= }1, {1:(c}ount or 1) do | + {1: } {1: } lo{1:ca}l c{1:el}l = line[colpos] | + {1: } {1: } ce{1:ll}.te{1:xt} = text | + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + {1:~ }| + {1:~ }| + | + ]]} + feed'5<c-e>' + screen:expect{grid=[[ + ^ {1: }f{1:or} _ {1:= }1, {1:(c}ount or 1) do | + {1: } {1: } lo{1:ca}l c{1:el}l = line[colpos] | + {1: } {1: } ce{1:ll}.te{1:xt} = text | + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + meths.buf_set_extmark(0, ns, 1, 0, { end_line=8, end_col=10, hl_group = 'ErrorMsg'}) + screen:expect{grid=[[ + {4:^ }{36: }{4:f}{36:or}{4: _ }{36:= }{4:1, }{36:(c}{4:ount or 1) do} | + {4: }{36: }{4: }{36: }{4: lo}{36:ca}{4:l c}{36:el}{4:l = line[colpos]} | + {4: }{36: }{4: }{36: }{4: ce}{36:ll}{4:.te}{36:xt}{4: = text} | + {4: ce}ll.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) + + local function with_undo_restore(val) + screen:try_resize(50, 5) + insert(example_text) + feed'gg' + meths.buf_set_extmark(0, ns, 0, 6, { end_col=13, hl_group = 'NonText', undo_restore=val}) + screen:expect{grid=[[ + ^for _,{1:item in} ipairs(items) do | + local text, hl_id_cell, count = unpack(item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + | + ]]} + + meths.buf_set_text(0, 0, 4, 0, 8, {''}) + screen:expect{grid=[[ + ^for {1:em in} ipairs(items) do | + local text, hl_id_cell, count = unpack(item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + | + ]]} + end + + it("highlights do reapply to restored text after delete", function() + with_undo_restore(true) -- also default behavior + + command('silent undo') + screen:expect{grid=[[ + ^for _,{1:item in} ipairs(items) do | + local text, hl_id_cell, count = unpack(item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + | + ]]} + end) + + it("highlights don't reapply to restored text after delete with undo_restore=false", function() + with_undo_restore(false) + + command('silent undo') + screen:expect{grid=[[ + ^for _,it{1:em in} ipairs(items) do | + local text, hl_id_cell, count = unpack(item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + | + ]]} + + eq({ { 1, 0, 8, { end_col = 13, end_right_gravity = false, end_row = 0, + hl_eol = false, hl_group = "NonText", undo_restore = false, + ns_id = 1, priority = 4096, right_gravity = true } } }, + meths.buf_get_extmarks(0, ns, {0,0}, {0, -1}, {details=true})) + end) + + it('virtual text works with rightleft', function() + screen:try_resize(50, 3) + insert('abcdefghijklmn') + feed('0') + command('set rightleft') + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'EOL', 'Underlined'}}}) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'right_align', 'Underlined'}}, virt_text_pos = 'right_align' }) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'win_col', 'Underlined'}}, virt_text_win_col = 20 }) + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'overlayed', 'Underlined'}}, virt_text_pos = 'overlay' }) + screen:expect{grid=[[ + {28:ngila_thgir} {28:loc_niw} {28:LOE} nml{28:deyalrevo}b^a| + {1: ~}| + | + ]]} + + insert(('#'):rep(32)) + feed('0') + screen:expect{grid=[[ + {28:ngila_tdeyalrevo}ba#####{28:loc_niw}###################^#| + {1: ~}| + | + ]]} + + insert(('#'):rep(16)) + feed('0') + screen:expect{grid=[[ + {28:ngila_thgir}############{28:loc_niw}###################^#| + {28:LOE} nml{28:deyalrevo}| + | + ]]} + + insert('###') + feed('0') + screen:expect{grid=[[ + #################################################^#| + {28:ngila_thgir} {28:loc_niw} {28:LOE} nml{28:deyalrevo}ba#| + | + ]]} + + command('set number') + screen:expect{grid=[[ + #############################################^#{2: 1 }| + {28:ngila_thgir} {28:loc_niw} nml{28:deyalrevo}ba#####{2: }| + | + ]]} + + command('set cpoptions+=n') + screen:expect{grid=[[ + #############################################^#{2: 1 }| + {28:ngila_thgir} {28:loc_niw} nml{28:deyalrevo}ba#####| + | + ]]} + end) + + it('works with double width char and rightleft', function() + screen:try_resize(50, 3) + insert('abcdefghij口klmnopqrstu口vwx口yz') + feed('0') + command('set rightleft') + screen:expect{grid=[[ + zy口xwv口utsrqponmlk口jihgfedcb^a| + {1: ~}| + | + ]]} + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'overlayed', 'Underlined'}}, virt_text_pos = 'overlay' }) + meths.buf_set_extmark(0, ns, 0, 14, { virt_text = {{'古', 'Underlined'}}, virt_text_pos = 'overlay' }) + meths.buf_set_extmark(0, ns, 0, 20, { virt_text = {{'\t', 'Underlined'}}, virt_text_pos = 'overlay' }) + meths.buf_set_extmark(0, ns, 0, 29, { virt_text = {{'古', 'Underlined'}}, virt_text_pos = 'overlay' }) + screen:expect{grid=[[ + zy {28:古}wv {28: }qpon{28:古}k {28:deyalrevo}b^a| + {1: ~}| + | + ]]} + end) + + it('works with both hl_group and sign_hl_group', function() + screen:try_resize(screen._width, 3) + insert('abcdefghijklmn') + meths.buf_set_extmark(0, ns, 0, 0, {sign_text='S', sign_hl_group='NonText', hl_group='Error', end_col=14}) + screen:expect{grid=[[ + {1:S }{4:abcdefghijklm^n} | + {1:~ }| + | + ]]} + end) +end) + +describe('decorations: inline virtual text', function() + local screen, ns + before_each( function() + clear() + screen = Screen.new(50, 3) + screen:attach() + screen:set_default_attr_ids { + [1] = {bold=true, foreground=Screen.colors.Blue}; + [2] = {foreground = Screen.colors.Brown}; + [3] = {bold = true, foreground = Screen.colors.SeaGreen}; + [4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100}; + [5] = {background = Screen.colors.Red1, bold = true}; + [6] = {foreground = Screen.colors.DarkCyan}; + [7] = {background = Screen.colors.LightGrey}; + [8] = {bold = true}; + [9] = {background = Screen.colors.Plum1}; + [10] = {foreground = Screen.colors.SlateBlue}; + [11] = {blend = 30, background = Screen.colors.Red1}; + [12] = {background = Screen.colors.Yellow}; + [13] = {reverse = true}; + [14] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightMagenta}; + [15] = {bold = true, reverse = true}; + [16] = {foreground = Screen.colors.Red}; + [17] = {background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue}; + [18] = {background = Screen.colors.LightGrey, foreground = Screen.colors.Red}; + [19] = {background = Screen.colors.Yellow, foreground = Screen.colors.SlateBlue}; + [20] = {background = Screen.colors.LightGrey, foreground = Screen.colors.SlateBlue}; + [21] = {reverse = true, foreground = Screen.colors.SlateBlue} + } + + ns = meths.create_namespace 'test' + end) + + + it('works', function() + screen:try_resize(50, 10) + insert(example_text) + feed 'gg' + screen:expect{grid=[[ + ^for _,item in ipairs(items) do | + local text, hl_id_cell, count = unpack(item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + cell.hl_id = hl_id | + | + ]]} + + meths.buf_set_extmark(0, ns, 1, 14, {virt_text={{': ', 'Special'}, {'string', 'Type'}}, virt_text_pos='inline'}) + screen:expect{grid=[[ + ^for _,item in ipairs(items) do | + local text{10:: }{3:string}, hl_id_cell, count = unpack| + (item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + | + ]]} + + screen:try_resize(55, 10) + screen:expect{grid=[[ + ^for _,item in ipairs(items) do | + local text{10:: }{3:string}, hl_id_cell, count = unpack(item| + ) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + | + ]]} + + screen:try_resize(56, 10) + screen:expect{grid=[[ + ^for _,item in ipairs(items) do | + local text{10:: }{3:string}, hl_id_cell, count = unpack(item)| + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + cell.hl_id = hl_id | + | + ]]} + end) + + it('works with 0-width chunk', function() + screen:try_resize(50, 10) + insert(example_text) + feed 'gg' + screen:expect{grid=[[ + ^for _,item in ipairs(items) do | + local text, hl_id_cell, count = unpack(item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + cell.hl_id = hl_id | + | + ]]} + + meths.buf_set_extmark(0, ns, 0, 5, {virt_text={{''}, {''}}, virt_text_pos='inline'}) + meths.buf_set_extmark(0, ns, 1, 14, {virt_text={{''}, {': ', 'Special'}}, virt_text_pos='inline'}) + meths.buf_set_extmark(0, ns, 1, 48, {virt_text={{''}, {''}}, virt_text_pos='inline'}) + screen:expect{grid=[[ + ^for _,item in ipairs(items) do | + local text{10:: }, hl_id_cell, count = unpack(item)| + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + cell.hl_id = hl_id | + | + ]]} + + meths.buf_set_extmark(0, ns, 1, 14, {virt_text={{''}, {'string', 'Type'}}, virt_text_pos='inline'}) + feed('V') + screen:expect{grid=[[ + ^f{7:or _,item in ipairs(items) do} | + local text{10:: }{3:string}, hl_id_cell, count = unpack| + (item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + {8:-- VISUAL LINE --} | + ]]} + + feed('<Esc>jf,') + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text{10:: }{3:string}^, hl_id_cell, count = unpack| + (item) | + if hl_id_cell ~= nil then | + hl_id = hl_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + cell.text = text | + | + ]]} + end) + + it('Normal mode "gM" command works properly', function() + command([[call setline(1, '123456789')]]) + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 7, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' }) + feed('gM') + screen:expect{grid=[[ + 12{10:bbb}34^567{10:bbb}89 | + {1:~ }| + | + ]]} + end) + + local function test_normal_gj_gk() + screen:try_resize(60, 6) + command([[call setline(1, repeat([repeat('a', 55)], 2))]]) + meths.buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(10), 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 1, 40, { virt_text = { { ('b'):rep(10), 'Special' } }, virt_text_pos = 'inline' }) + screen:expect{grid=[[ + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + {1:~ }| + | + ]]} + feed('gj') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + ^aaaaa | + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + {1:~ }| + | + ]]} + feed('gj') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + {1:~ }| + | + ]]} + feed('gj') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + ^aaaaa | + {1:~ }| + | + ]]} + feed('gk') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + {1:~ }| + | + ]]} + feed('gk') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + ^aaaaa | + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + {1:~ }| + | + ]]} + feed('gk') + screen:expect{grid=[[ + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| + aaaaa | + {1:~ }| + | + ]]} + end + + describe('Normal mode "gj" "gk" commands work properly', function() + it('with virtualedit=', function() + test_normal_gj_gk() + end) + + it('with virtualedit=all', function() + command('set virtualedit=all') + test_normal_gj_gk() + end) + end) + + it('cursor positions are correct with multiple inline virtual text', function() + insert('12345678') + meths.buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' }) + feed '^' + feed '4l' + screen:expect{grid=[[ + 1234{10: virtual text virtual text }^5678 | + {1:~ }| + | + ]]} + end) + + it('adjusts cursor location correctly when inserting around inline virtual text', function() + insert('12345678') + feed '$' + meths.buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' }) + + screen:expect{grid=[[ + 1234{10: virtual text }567^8 | + {1:~ }| + | + ]]} + end) + + it('has correct highlighting with multi-byte characters', function() + insert('12345678') + meths.buf_set_extmark(0, ns, 0, 4, { virt_text = { { 'múlti-byté chñröcters 修补', 'Special' } }, virt_text_pos = 'inline' }) + + screen:expect{grid=[[ + 1234{10:múlti-byté chñröcters 修补}567^8 | + {1:~ }| + | + ]]} + end) + + it('has correct cursor position when inserting around virtual text', function() + insert('12345678') + meths.buf_set_extmark(0, ns, 0, 4, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + feed '^' + feed '3l' + feed 'a' + screen:expect{grid=[[ + 1234{10:^virtual text}5678 | + {1:~ }| + {8:-- INSERT --} | + ]]} + feed '<ESC>' + screen:expect{grid=[[ + 123^4{10:virtual text}5678 | + {1:~ }| + | + ]]} + feed '^' + feed '4l' + feed 'i' + screen:expect{grid=[[ + 1234{10:^virtual text}5678 | + {1:~ }| + {8:-- INSERT --} | + ]]} + end) + + it('has correct cursor position with virtual text on an empty line', function() + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + screen:expect{grid=[[ + {10:^virtual text} | + {1:~ }| + | + ]]} + end) + + it('text is drawn correctly with a wrapping virtual text', function() + screen:try_resize(60, 8) + exec([[ + call setline(1, ['', 'aaa', '', 'bbbbbb']) + normal gg0 + ]]) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('X', 60), 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 2, 0, { virt_text = { { string.rep('X', 61), 'Special' } }, virt_text_pos = 'inline' }) + feed('$') + screen:expect{grid=[[ + {10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + aaa | + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:X} | + bbbbbb | + {1:~ }| + {1:~ }| + | + ]]} + feed('j') + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + aa^a | + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:X} | + bbbbbb | + {1:~ }| + {1:~ }| + | + ]]} + feed('j') + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + aaa | + {10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:X} | + bbbbbb | + {1:~ }| + {1:~ }| + | + ]]} + feed('j') + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + aaa | + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:X} | + bbbbb^b | + {1:~ }| + {1:~ }| + | + ]]} + feed('0<C-V>2l2k') + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {7:aa}^a | + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:X} | + {7:bbb}bbb | + {1:~ }| + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed([[<Esc>/aaa\n\%V<CR>]]) + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {12:^aaa } | + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:X} | + bbbbbb | + {1:~ }| + {1:~ }| + {16:search hit BOTTOM, continuing at TOP} | + ]]} + feed('3ggic') + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {12:aaa } | + c{10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:XX} | + bbbbbb | + {1:~ }| + {1:~ }| + {8:-- INSERT --} | + ]]} + feed([[<Esc>/aaa\nc\%V<CR>]]) + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {12:^aaa } | + {12:c}{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:XX} | + bbbbbb | + {1:~ }| + {1:~ }| + {16:search hit BOTTOM, continuing at TOP} | + ]]} + end) + + it('cursor position is correct with virtual text attached to hard TABs', function() + command('set noexpandtab') + feed('i') + feed('<TAB>') + feed('<TAB>') + feed('test') + feed('<ESC>') + meths.buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + feed('0') + screen:expect{grid=[[ + ^ {10:virtual text} test | + {1:~ }| + | + ]]} + + feed('l') + screen:expect{grid=[[ + {10:virtual text} ^ test | + {1:~ }| + | + ]]} + + feed('l') + screen:expect{grid=[[ + {10:virtual text} ^test | + {1:~ }| + | + ]]} + + feed('l') + screen:expect{grid=[[ + {10:virtual text} t^est | + {1:~ }| + | + ]]} + + feed('l') + screen:expect{grid=[[ + {10:virtual text} te^st | + {1:~ }| + | + ]]} + end) + + it('cursor position is correct with virtual text on an empty line', function() + command('set linebreak') + insert('one twoword') + feed('0') + meths.buf_set_extmark(0, ns, 0, 3, { virt_text = { { ': virtual text', 'Special' } }, virt_text_pos = 'inline' }) + screen:expect{grid=[[ + ^one{10:: virtual text} twoword | + {1:~ }| + | + ]]} + end) + + it('search highlight is correct', function() + insert('foo foo foo bar\nfoo foo foo bar') + feed('gg0') + meths.buf_set_extmark(0, ns, 0, 9, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 9, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 1, 9, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 1, 9, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) + screen:expect{grid=[[ + ^foo foo f{10:AAABBB}oo bar | + foo foo f{10:CCCDDD}oo bar | + | + ]]} + + feed('/foo') + screen:expect{grid=[[ + {12:foo} {13:foo} {12:f}{10:AAA}{19:BBB}{12:oo} bar | + {12:foo} {12:foo} {12:f}{19:CCC}{10:DDD}{12:oo} bar | + /foo^ | + ]]} + + meths.buf_set_extmark(0, ns, 0, 13, { virt_text = { { 'EEE', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + feed('<C-G>') + screen:expect{grid=[[ + {12:foo} {12:foo} {13:f}{10:AAA}{21:BBB}{13:oo} b{10:EEE}ar | + {12:foo} {12:foo} {12:f}{19:CCC}{10:DDD}{12:oo} bar | + /foo^ | + ]]} + end) + + it('Visual select highlight is correct', function() + insert('foo foo foo bar\nfoo foo foo bar') + feed('gg0') + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) + feed('8l') + screen:expect{grid=[[ + foo foo {10:AAABBB}^foo bar | + foo foo {10:CCCDDD}foo bar | + | + ]]} + + feed('<C-V>') + feed('2hj') + screen:expect{grid=[[ + foo fo{7:o }{10:AAA}{20:BBB}{7:f}oo bar | + foo fo^o{7: }{20:CCC}{10:DDD}{7:f}oo bar | + {8:-- VISUAL BLOCK --} | + ]]} + + meths.buf_set_extmark(0, ns, 0, 10, { virt_text = { { 'EEE', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + screen:expect{grid=[[ + foo fo{7:o }{10:AAA}{20:BBB}{7:f}o{10:EEE}o bar | + foo fo^o{7: }{20:CCC}{10:DDD}{7:f}oo bar | + {8:-- VISUAL BLOCK --} | + ]]} + end) + + it('inside highlight range of another extmark', function() + insert('foo foo foo bar\nfoo foo foo bar') + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) + meths.buf_set_extmark(0, ns, 0, 4, { end_col = 11, hl_group = 'Search' }) + meths.buf_set_extmark(0, ns, 1, 4, { end_col = 11, hl_group = 'Search' }) + screen:expect{grid=[[ + foo {12:foo }{10:AAA}{19:BBB}{12:foo} bar | + foo {12:foo }{19:CCC}{10:DDD}{12:foo} ba^r | + | + ]]} + end) + + it('inside highlight range of syntax', function() + insert('foo foo foo bar\nfoo foo foo bar') + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) + command([[syntax match Search 'foo \zsfoo foo\ze bar']]) + screen:expect{grid=[[ + foo {12:foo }{10:AAA}{19:BBB}{12:foo} bar | + foo {12:foo }{19:CCC}{10:DDD}{12:foo} ba^r | + | + ]]} + end) + + it('cursor position is correct when inserting around a virtual text with left gravity', function() + screen:try_resize(27, 4) + insert(('a'):rep(15)) + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = { { ('>'):rep(43), 'Special' } }, virt_text_pos = 'inline', right_gravity = false }) + command('setlocal showbreak=+ breakindent breakindentopt=shift:2') + feed('08l') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}^aaaaaaa | + | + ]]} + feed('i') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}^aaaaaaa | + {8:-- INSERT --} | + ]]} + feed([[<C-\><C-O>]]) + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}^aaaaaaa | + {8:-- (insert) --} | + ]]} + feed('D') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:^~ }| + {8:-- INSERT --} | + ]]} + command('setlocal list listchars=eol:$') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+^$} | + {8:-- INSERT --} | + ]]} + feed('<C-U>') + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>}{1:^$} | + {1:~ }| + {8:-- INSERT --} | + ]]} + feed('a') + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>}a{1:^$} | + {1:~ }| + {8:-- INSERT --} | + ]]} + feed('<Esc>') + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>}^a{1:$} | + {1:~ }| + | + ]]} + feed('x') + screen:expect{grid=[[ + {10:^>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>>>>>>>}{1:$} | + {1:~ }| + | + ]]} + end) + + it('cursor position is correct when inserting around virtual texts with both left and right gravity', function() + screen:try_resize(30, 4) + command('setlocal showbreak=+ breakindent breakindentopt=shift:2') + insert(('a'):rep(15)) + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = {{ ('>'):rep(32), 'Special' }}, virt_text_pos = 'inline', right_gravity = false }) + meths.buf_set_extmark(0, ns, 0, 8, { virt_text = {{ ('<'):rep(32), 'Special' }}, virt_text_pos = 'inline', right_gravity = true }) + feed('08l') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>><<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<<<<<<<<<}^aaaaaaa | + | + ]]} + feed('i') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>^<<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<<<<<<<<<}aaaaaaa | + {8:-- INSERT --} | + ]]} + feed('a') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>}a{10:^<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<<<<<<<<<<}aaaaaaa | + {8:-- INSERT --} | + ]]} + feed([[<C-\><C-O>]]) + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>}a{10:<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<<<<<<<<<<}^aaaaaaa | + {8:-- (insert) --} | + ]]} + feed('D') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>}a{10:^<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<<<<<<<<<<} | + {8:-- INSERT --} | + ]]} + feed('<BS>') + screen:expect{grid=[[ + aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>>>>>>>>>^<<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<<<<<<<<<} | + {8:-- INSERT --} | + ]]} + feed('<C-U>') + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>^<<<<<<<<<<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<} | + {8:-- INSERT --} | + ]]} + feed('a') + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>}a{10:^<<<<<<<<<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<<} | + {8:-- INSERT --} | + ]]} + feed('<Esc>') + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>}^a{10:<<<<<<<<<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<<} | + | + ]]} + feed('x') + screen:expect{grid=[[ + {10:^>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>><<<<<<<<<<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<} | + | + ]]} + feed('i') + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:>>^<<<<<<<<<<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<<<<<} | + {8:-- INSERT --} | + ]]} + screen:try_resize(32, 4) + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<}| + {1:+}{10:<<<} | + {8:-- INSERT --} | + ]]} + command('setlocal nobreakindent') + screen:expect{grid=[[ + {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| + {1:+}{10:^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<}| + {1:+}{10:<} | + {8:-- INSERT --} | + ]]} + end) + + it('draws correctly with no wrap multiple virtual text, where one is hidden', function() + insert('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz') + command("set nowrap") + meths.buf_set_extmark(0, ns, 0, 50, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + feed('$') + screen:expect{grid=[[ + opqrstuvwxyzabcdefghijklmnopqrstuvwx{10:virtual text}y^z| + {1:~ }| + | + ]]} + end) + + it('draws correctly with no wrap and a long virtual text', function() + insert('abcdefghi') + command("set nowrap") + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' }) + feed('$') + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i| + {1:~ }| + | + ]]} + end) + + it('tabs are the correct length with no wrap following virtual text', function() + command('set nowrap') + feed('itest<TAB>a<ESC>') + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' }) + feed('gg$') + screen:expect{grid=[[ + {10:aaaaaaaaaaaaaaaaaaaaaaaaa}test ^a | + {1:~ }| + | + ]]} + end) + + it('highlighting does not extend with no wrap and a long virtual text', function() + insert('abcdef') + command("set nowrap") + meths.buf_set_extmark(0, ns, 0, 3, { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline' }) + feed('$') + screen:expect{grid=[[ + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}de^f| + {1:~ }| + | + ]]} + end) + + it('hidden virtual text does not interfere with Visual highlight', function() + insert('abcdef') + command('set nowrap') + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'XXX', 'Special' } }, virt_text_pos = 'inline' }) + feed('V2zl') + screen:expect{grid=[[ + {10:X}{7:abcde}^f | + {1:~ }| + {8:-- VISUAL LINE --} | + ]]} + feed('zl') + screen:expect{grid=[[ + {7:abcde}^f | + {1:~ }| + {8:-- VISUAL LINE --} | + ]]} + feed('zl') + screen:expect{grid=[[ + {7:bcde}^f | + {1:~ }| + {8:-- VISUAL LINE --} | + ]]} + end) + + it('highlighting is correct when virtual text wraps with number', function() + screen:try_resize(50, 5) + insert([[ + test + test]]) + command('set number') + meths.buf_set_extmark(0, ns, 0, 1, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' }) + feed('gg0') + screen:expect{grid=[[ + {2: 1 }^t{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {2: }{10:XXXXXXXXXX}est | + {2: 2 }test | + {1:~ }| + | + ]]} + end) + + it('highlighting is correct when virtual text is proceeded with a match', function() + insert([[test]]) + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + feed('gg0') + command('match ErrorMsg /e/') + screen:expect{grid=[[ + ^t{4:e}{10:virtual text}st | + {1:~ }| + | + ]]} + command('match ErrorMsg /s/') + screen:expect{grid=[[ + ^te{10:virtual text}{4:s}t | + {1:~ }| + | + ]]} + end) + + it('smoothscroll works correctly when virtual text wraps', function() + insert('foobar') + meths.buf_set_extmark(0, ns, 0, 3, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' }) + command('setlocal smoothscroll') + screen:expect{grid=[[ + foo{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:XXXXXXXX}ba^r | + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:<<<}{10:XXXXX}ba^r | + {1:~ }| + | + ]]} + end) + + it('in diff mode is highlighted correct', function() + screen:try_resize(50, 10) + insert([[ + 9000 + 0009 + 0009 + 9000 + 0009 + ]]) + insert('aaa\tbbb') + command("set diff") + meths.buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline', right_gravity = false }) + meths.buf_set_extmark(0, ns, 5, 0, { virt_text = { { '!', 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 5, 3, { virt_text = { { '' } }, virt_text_pos = 'inline' }) + command("vnew") + insert([[ + 000 + 000 + 000 + 000 + 000 + ]]) + insert('aaabbb') + command("set diff") + feed('gg0') + screen:expect{grid=[[ + {9:^000 }│{5:9}{14:test}{9:000 }| + {9:000 }│{9:000}{5:9}{9: }| + {9:000 }│{9:000}{5:9}{9: }| + {9:000 }│{5:9}{9:000 }| + {9:000 }│{9:000}{5:9}{9: }| + {9:aaabbb }│{14:!}{9:aaa}{5: }{9:bbb }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {15:[No Name] [+] }{13:[No Name] [+] }| + | + ]]} + command('wincmd w | set nowrap') + feed('zl') + screen:expect{grid=[[ + {9:000 }│{14:test}{9:000 }| + {9:000 }│{9:00}{5:9}{9: }| + {9:000 }│{9:00}{5:9}{9: }| + {9:000 }│{9:000 }| + {9:000 }│{9:00}{5:9}{9: }| + {9:aaabbb }│{9:aaa}{5: }{9:bb^b }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {13:[No Name] [+] }{15:[No Name] [+] }| + | + ]]} + end) + + it('correctly draws when there are multiple overlapping virtual texts on the same line with nowrap', function() + command('set nowrap') + insert('a') + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('b', 55), 'Special' } }, virt_text_pos = 'inline' }) + feed('$') + screen:expect{grid=[[ + {10:bbbbbbbbbbbbbbbbbbbbbbbbb}^a | + {1:~ }| + | + ]]} + end) + + it('correctly draws when overflowing virtual text is followed by TAB with no wrap', function() + command('set nowrap') + feed('i<TAB>test<ESC>') + meths.buf_set_extmark( 0, ns, 0, 0, { virt_text = { { string.rep('a', 60), 'Special' } }, virt_text_pos = 'inline' }) + feed('0') + screen:expect({grid=[[ + {10:aaaaaaaaaaaaaaaaaaaaaa} ^ test | + {1:~ }| + | + ]]}) + end) + + it('does not crash at column 0 when folded in a wide window', function() + screen:try_resize(82, 5) + command('hi! CursorLine guibg=NONE guifg=Red gui=NONE') + command('set cursorline') + insert([[ + aaaaa + bbbbb + + ccccc]]) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'foo'}}, virt_text_pos = 'inline' }) + meths.buf_set_extmark(0, ns, 2, 0, { virt_text = {{'bar'}}, virt_text_pos = 'inline' }) + screen:expect{grid=[[ + fooaaaaa | + bbbbb | + bar | + {16:cccc^c }| + | + ]]} + command('1,2fold') + screen:expect{grid=[[ + {17:+-- 2 lines: aaaaa·······························································}| + bar | + {16:cccc^c }| + {1:~ }| + | + ]]} + feed('2k') + screen:expect{grid=[[ + {18:^+-- 2 lines: aaaaa·······························································}| + bar | + ccccc | + {1:~ }| + | + ]]} + command('3,4fold') + screen:expect{grid=[[ + {18:^+-- 2 lines: aaaaa·······························································}| + {17:+-- 2 lines: ccccc·······························································}| + {1:~ }| + {1:~ }| + | + ]]} + feed('j') + screen:expect{grid=[[ + {17:+-- 2 lines: aaaaa·······························································}| + {18:^+-- 2 lines: ccccc·······························································}| + {1:~ }| + {1:~ }| + | + ]]} + end) + + it('does not crash at right edge of wide window #23848', function() + screen:try_resize(82, 5) + meths.buf_set_extmark(0, ns, 0, 0, {virt_text = {{('a'):rep(82)}, {'b'}}, virt_text_pos = 'inline'}) + screen:expect{grid=[[ + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + b | + {1:~ }| + {1:~ }| + | + ]]} + command('set nowrap') + screen:expect{grid=[[ + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + feed('82i0<Esc>0') + screen:expect{grid=[[ + ^0000000000000000000000000000000000000000000000000000000000000000000000000000000000| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + command('set wrap') + screen:expect{grid=[[ + ^0000000000000000000000000000000000000000000000000000000000000000000000000000000000| + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + b | + {1:~ }| + | + ]]} + end) + + it('lcs-extends is drawn with inline virtual text at end of screen line', function() + exec([[ + setlocal nowrap list listchars=extends:! + call setline(1, repeat('a', 51)) + ]]) + meths.buf_set_extmark(0, ns, 0, 50, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' }) + feed('20l') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:!}| + {1:~ }| + | + ]]} + feed('zl') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:!}| + {1:~ }| + | + ]]} + feed('zl') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:b}{1:!}| + {1:~ }| + | + ]]} + feed('zl') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bb}{1:!}| + {1:~ }| + | + ]]} + feed('zl') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbb}a| + {1:~ }| + | + ]]} + end) + + it('lcs-extends is drawn with only inline virtual text offscreen', function() + command('set nowrap') + command('set list') + command('set listchars+=extends:c') + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline' }) + insert(string.rep('a', 50)) + feed('gg0') + screen:expect{grid=[[ + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:c}| + {1:~ }| + | + ]]} + end) + + it('blockwise Visual highlight with double-width virtual text (replace)', function() + screen:try_resize(60, 6) + insert('123456789\n123456789\n123456789\n123456789') + meths.buf_set_extmark(0, ns, 1, 1, { virt_text = { { '-口-', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) + meths.buf_set_extmark(0, ns, 2, 2, { virt_text = { { '口', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) + feed('gg0') + screen:expect{grid=[[ + ^123456789 | + 1{10:-口-}23456789 | + 12{10:口}3456789 | + 123456789 | + {1:~ }| + | + ]]} + feed('<C-V>3jl') + screen:expect{grid=[[ + {7:12}3456789 | + {7:1}{10:-口-}23456789 | + {7:12}{10:口}3456789 | + {7:1}^23456789 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('l') + screen:expect{grid=[[ + {7:123}456789 | + {7:1}{10:-口-}23456789 | + {7:12}{10:口}3456789 | + {7:12}^3456789 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('4l') + screen:expect{grid=[[ + {7:1234567}89 | + {7:1}{10:-口-}{7:23}456789 | + {7:12}{10:口}{7:345}6789 | + {7:123456}^789 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('Ol') + screen:expect{grid=[[ + 1{7:234567}89 | + 1{10:-口-}{7:23}456789 | + 1{7:2}{10:口}{7:345}6789 | + 1^2{7:34567}89 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('l') + screen:expect{grid=[[ + 12{7:34567}89 | + 1{10:-口-}{7:23}456789 | + 12{10:口}{7:345}6789 | + 12^3{7:4567}89 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('l') + screen:expect{grid=[[ + 123{7:4567}89 | + 1{10:-口-}{7:23}456789 | + 12{10:口}{7:345}6789 | + 123^4{7:567}89 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + end) + + it('blockwise Visual highlight with double-width virtual text (combine)', function() + screen:try_resize(60, 6) + insert('123456789\n123456789\n123456789\n123456789') + meths.buf_set_extmark(0, ns, 1, 1, { virt_text = { { '-口-', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 2, 2, { virt_text = { { '口', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) + feed('gg0') + screen:expect{grid=[[ + ^123456789 | + 1{10:-口-}23456789 | + 12{10:口}3456789 | + 123456789 | + {1:~ }| + | + ]]} + feed('<C-V>3jl') + screen:expect{grid=[[ + {7:12}3456789 | + {7:1}{20:-}{10:口-}23456789 | + {7:12}{10:口}3456789 | + {7:1}^23456789 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('l') + screen:expect{grid=[[ + {7:123}456789 | + {7:1}{20:-口}{10:-}23456789 | + {7:12}{20:口}3456789 | + {7:12}^3456789 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('4l') + screen:expect{grid=[[ + {7:1234567}89 | + {7:1}{20:-口-}{7:23}456789 | + {7:12}{20:口}{7:345}6789 | + {7:123456}^789 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('Ol') + screen:expect{grid=[[ + 1{7:234567}89 | + 1{20:-口-}{7:23}456789 | + 1{7:2}{20:口}{7:345}6789 | + 1^2{7:34567}89 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('l') + screen:expect{grid=[[ + 12{7:34567}89 | + 1{10:-}{20:口-}{7:23}456789 | + 12{20:口}{7:345}6789 | + 12^3{7:4567}89 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + feed('l') + screen:expect{grid=[[ + 123{7:4567}89 | + 1{10:-}{20:口-}{7:23}456789 | + 12{20:口}{7:345}6789 | + 123^4{7:567}89 | + {1:~ }| + {8:-- VISUAL BLOCK --} | + ]]} + end) + + local function test_virt_inline_showbreak_smoothscroll() + screen:try_resize(30, 6) + exec([[ + highlight! link LineNr Normal + setlocal number showbreak=+ breakindent breakindentopt=shift:2 + setlocal scrolloff=0 smoothscroll + call setline(1, repeat('a', 28)) + normal! $ + ]]) + meths.buf_set_extmark(0, ns, 0, 27, { virt_text = { { ('123'):rep(23) } }, virt_text_pos = 'inline' }) + feed(':<CR>') -- Have a screen line that doesn't start with spaces + screen:expect{grid=[[ + 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:+}a1231231231231231231231| + {1:+}23123123123123123123123| + {1:+}12312312312312312312312| + {1:+}3^a | + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}a1231231231231231231231| + {1:+}23123123123123123123123| + {1:+}12312312312312312312312| + {1:+}3^a | + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}23123123123123123123123| + {1:+}12312312312312312312312| + {1:+}3^a | + {1:~ }| + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}12312312312312312312312| + {1:+}3^a | + {1:~ }| + {1:~ }| + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}3^a | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + : | + ]]} + feed('zbi') + screen:expect{grid=[[ + 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:+}a^1231231231231231231231| + {1:+}23123123123123123123123| + {1:+}12312312312312312312312| + {1:+}3a | + {8:-- INSERT --} | + ]]} + feed('<BS>') + screen:expect{grid=[[ + 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:+}^12312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123123| + {1:+}a | + {8:-- INSERT --} | + ]]} + feed('<Esc>l') + feed(':<CR>') -- Have a screen line that doesn't start with spaces + screen:expect{grid=[[ + 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:+}12312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123123| + {1:+}^a | + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}12312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123123| + {1:+}^a | + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}31231231231231231231231| + {1:+}23123123123123123123123| + {1:+}^a | + {1:~ }| + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}23123123123123123123123| + {1:+}^a | + {1:~ }| + {1:~ }| + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}^a | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + : | + ]]} + feed('023x$') + screen:expect{grid=[[ + 1 aaa12312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123123| + {1:+}^a | + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}31231231231231231231231| + {1:+}23123123123123123123123| + {1:+}^a | + {1:~ }| + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}23123123123123123123123| + {1:+}^a | + {1:~ }| + {1:~ }| + {1:~ }| + : | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}^a | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + : | + ]]} + feed('zbi') + screen:expect{grid=[[ + 1 aaa^12312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123123| + {1:+}a | + {1:~ }| + {8:-- INSERT --} | + ]]} + feed('<C-U>') + screen:expect{grid=[[ + 1 ^12312312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123a | + {1:~ }| + {1:~ }| + {8:-- INSERT --} | + ]]} + feed('<Esc>') + screen:expect{grid=[[ + 1 12312312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123^a | + {1:~ }| + {1:~ }| + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}31231231231231231231231| + {1:+}23123123123123123123^a | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:+}23123123123123123123^a | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + feed('zbx') + screen:expect{grid=[[ + 1 ^12312312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123 | + {1:~ }| + {1:~ }| + | + ]]} + feed('26ia<Esc>a') + screen:expect{grid=[[ + 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:+}^12312312312312312312312| + {1:+}31231231231231231231231| + {1:+}23123123123123123123123| + {1:~ }| + {8:-- INSERT --} | + ]]} + feed([[<C-\><C-O>:setlocal breakindentopt=<CR>]]) + screen:expect{grid=[[ + 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:+}^1231231231231231231231231| + {1:+}2312312312312312312312312| + {1:+}3123123123123123123 | + {1:~ }| + {8:-- INSERT --} | + ]]} + end + + describe('with showbreak, smoothscroll', function() + it('and cpoptions-=n', function() + test_virt_inline_showbreak_smoothscroll() + end) + + it('and cpoptions+=n', function() + command('set cpoptions+=n') + -- because of 'breakindent' the screen states are the same + test_virt_inline_showbreak_smoothscroll() + end) + end) + + it('before TABs with smoothscroll', function() + screen:try_resize(30, 6) + exec([[ + setlocal list listchars=tab:<-> scrolloff=0 smoothscroll + call setline(1, repeat("\t", 4) .. 'a') + normal! $ + ]]) + meths.buf_set_extmark(0, ns, 0, 3, { virt_text = { { ('12'):rep(32) } }, virt_text_pos = 'inline' }) + screen:expect{grid=[[ + {1:<------><------><------>}121212| + 121212121212121212121212121212| + 1212121212121212121212121212{1:<-}| + {1:----->}^a | + {1:~ }| + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:<<<}212121212121212121212121212| + 1212121212121212121212121212{1:<-}| + {1:----->}^a | + {1:~ }| + {1:~ }| + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:<<<}2121212121212121212121212{1:<-}| + {1:----->}^a | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:<<<-->}^a | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + feed('zbh') + screen:expect{grid=[[ + {1:<------><------><------>}121212| + 121212121212121212121212121212| + 1212121212121212121212121212{1:^<-}| + {1:----->}a | + {1:~ }| + | + ]]} + feed('i') + screen:expect{grid=[[ + {1:<------><------><------>}^121212| + 121212121212121212121212121212| + 1212121212121212121212121212{1:<-}| + {1:----->}a | + {1:~ }| + {8:-- INSERT --} | + ]]} + feed('<C-O>:setlocal nolist<CR>') + screen:expect{grid=[[ + ^121212| + 121212121212121212121212121212| + 1212121212121212121212121212 | + a | + {1:~ }| + {8:-- INSERT --} | + ]]} + feed('<Esc>l') + screen:expect{grid=[[ + 121212| + 121212121212121212121212121212| + 1212121212121212121212121212 | + ^ a | + {1:~ }| + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:<<<}212121212121212121212121212| + 1212121212121212121212121212 | + ^ a | + {1:~ }| + {1:~ }| + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:<<<}2121212121212121212121212 | + ^ a | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + feed('<C-E>') + screen:expect{grid=[[ + {1:<<<} ^ a | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) + + it('before a space with linebreak', function() + screen:try_resize(50, 6) + exec([[ + setlocal linebreak showbreak=+ breakindent breakindentopt=shift:2 + call setline(1, repeat('a', 50) .. ' ' .. repeat('c', 45)) + normal! $ + ]]) + meths.buf_set_extmark(0, ns, 0, 50, { virt_text = { { ('b'):rep(10) } }, virt_text_pos = 'inline' }) + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:+}bbbbbbbbbb | + {1:+}cccccccccccccccccccccccccccccccccccccccccccc^c | + {1:~ }| + {1:~ }| + | + ]]} + feed('05x$') + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb| + {1:+}bbbbb | + {1:+}cccccccccccccccccccccccccccccccccccccccccccc^c | + {1:~ }| + {1:~ }| + | + ]]} + end) + + it('before double-width char that wraps', function() + exec([[ + call setline(1, repeat('a', 40) .. '口' .. '12345') + normal! $ + ]]) + meths.buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(9) } }, virt_text_pos = 'inline' }) + screen:expect{grid=[[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| + 口1234^5 | + | + ]]} + end) end) describe('decorations: virtual lines', function() @@ -1055,7 +3781,7 @@ describe('decorations: virtual lines', function() screen:attach() screen:set_default_attr_ids { [1] = {bold=true, foreground=Screen.colors.Blue}; - [2] = {foreground = Screen.colors.Cyan4}; + [2] = {foreground = Screen.colors.DarkCyan}; [3] = {background = Screen.colors.Yellow1}; [4] = {bold = true}; [5] = {background = Screen.colors.Yellow, foreground = Screen.colors.Blue}; @@ -1068,7 +3794,7 @@ describe('decorations: virtual lines', function() ns = meths.create_namespace 'test' end) - local example_text = [[ + local example_text2 = [[ if (h->n_buckets < new_n_buckets) { // expand khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); h->keys = new_keys; @@ -1079,7 +3805,7 @@ if (h->n_buckets < new_n_buckets) { // expand }]] it('works with one line', function() - insert(example_text) + insert(example_text2) feed 'gg' meths.buf_set_extmark(0, ns, 1, 33, { virt_lines={ {{">> ", "NonText"}, {"krealloc", "Identifier"}, {": change the size of an allocation"}}}; @@ -1170,6 +3896,7 @@ if (h->n_buckets < new_n_buckets) { // expand ]]} meths.buf_clear_namespace(0, ns, 0, -1) + -- Cursor should be drawn on the correct line. #22704 screen:expect{grid=[[ if (h->n_buckets < new_n_buckets) { // expand | khkey_t *new_keys = (khkey_t *) | @@ -1177,8 +3904,8 @@ if (h->n_buckets < new_n_buckets) { // expand hkey_t)); | h->keys = new_keys; | if (kh_is_map && val_size) { | - char *new_vals = {3:krealloc}( h->vals_buf, new_n_| - buck^ets * val_size); | + ^char *new_vals = {3:krealloc}( h->vals_buf, new_n_| + buckets * val_size); | h->vals_buf = new_vals; | } | } | @@ -1186,9 +3913,8 @@ if (h->n_buckets < new_n_buckets) { // expand ]]} end) - it('works with text at the beginning of the buffer', function() - insert(example_text) + insert(example_text2) feed 'gg' screen:expect{grid=[[ @@ -1249,7 +3975,7 @@ if (h->n_buckets < new_n_buckets) { // expand end) it('works with text at the end of the buffer', function() - insert(example_text) + insert(example_text2) feed 'G' screen:expect{grid=[[ @@ -1368,7 +4094,7 @@ if (h->n_buckets < new_n_buckets) { // expand end) it('works beyond end of the buffer with virt_lines_above', function() - insert(example_text) + insert(example_text2) feed 'G' screen:expect{grid=[[ @@ -1639,7 +4365,7 @@ if (h->n_buckets < new_n_buckets) { // expand end) it('works with sign and numbercolumns', function() - insert(example_text) + insert(example_text2) feed 'gg' command 'set number signcolumn=yes' screen:expect{grid=[[ @@ -1704,8 +4430,8 @@ if (h->n_buckets < new_n_buckets) { // expand end) - it('works with hard tabs', function() - insert(example_text) + it('works with hard TABs', function() + insert(example_text2) feed 'gg' meths.buf_set_extmark(0, ns, 1, 0, { virt_lines={ {{">>", "NonText"}, {"\tvery\ttabby", "Identifier"}, {"text\twith\ttabs"}}}; @@ -1774,6 +4500,106 @@ if (h->n_buckets < new_n_buckets) { // expand ]]} end) + it('does not show twice if end_row or end_col is specified #18622', function() + screen:try_resize(50, 8) + insert([[ + aaa + bbb + ccc + ddd]]) + meths.buf_set_extmark(0, ns, 0, 0, {end_row = 2, virt_lines = {{{'VIRT LINE 1', 'NonText'}}}}) + meths.buf_set_extmark(0, ns, 3, 0, {end_col = 2, virt_lines = {{{'VIRT LINE 2', 'NonText'}}}}) + screen:expect{grid=[[ + aaa | + {1:VIRT LINE 1} | + bbb | + ccc | + dd^d | + {1:VIRT LINE 2} | + {1:~ }| + | + ]]} + end) + + it('works with rightleft', function() + screen:try_resize(50, 8) + insert([[ + aaa + bbb + ccc + ddd]]) + command('set number rightleft') + meths.buf_set_extmark(0, ns, 0, 0, {virt_lines = {{{'VIRT LINE 1', 'NonText'}}}, virt_lines_leftcol = true}) + meths.buf_set_extmark(0, ns, 3, 0, {virt_lines = {{{'VIRT LINE 2', 'NonText'}}}}) + screen:expect{grid=[[ + aaa{9: 1 }| + {1:1 ENIL TRIV}| + bbb{9: 2 }| + ccc{9: 3 }| + ^ddd{9: 4 }| + {1:2 ENIL TRIV}{9: }| + {1: ~}| + | + ]]} + end) + + it('works when using dd or yyp #23915 #23916', function() + insert([[ + line1 + line2 + line3 + line4 + line5]]) + meths.buf_set_extmark(0, ns, 0, 0, {virt_lines={{{"foo"}}, {{"bar"}}, {{"baz"}}}}) + screen:expect{grid=[[ + line1 | + foo | + bar | + baz | + line2 | + line3 | + line4 | + line^5 | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('gg') + feed('dd') + screen:expect{grid=[[ + ^line2 | + foo | + bar | + baz | + line3 | + line4 | + line5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('yyp') + screen:expect{grid=[[ + line2 | + foo | + bar | + baz | + ^line2 | + line3 | + line4 | + line5 | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) + end) describe('decorations: signs', function() @@ -1789,10 +4615,10 @@ describe('decorations: signs', function() } ns = meths.create_namespace 'test' - meths.win_set_option(0, 'signcolumn', 'auto:9') + meths.set_option_value('signcolumn', 'auto:9', {}) end) - local example_text = [[ + local example_test3 = [[ l1 l2 l3 @@ -1801,7 +4627,7 @@ l5 ]] it('can add a single sign (no end row)', function() - insert(example_text) + insert(example_test3) feed 'gg' meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S'}) @@ -1822,7 +4648,7 @@ l5 end) it('can add a single sign (with end row)', function() - insert(example_text) + insert(example_test3) feed 'gg' meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row=1}) @@ -1842,9 +4668,29 @@ l5 end) + it('can add a single sign and text highlight', function() + insert(example_test3) + feed 'gg' + + meths.buf_set_extmark(0, ns, 1, 0, {sign_text='S', hl_group='Todo', end_col=1}) + screen:expect{grid=[[ + {1: }^l1 | + S {3:l}2 | + {1: }l3 | + {1: }l4 | + {1: }l5 | + {1: } | + {2:~ }| + {2:~ }| + {2:~ }| + | + ]]} + + meths.buf_clear_namespace(0, ns, 0, -1) + end) + it('can add multiple signs (single extmark)', function() - pending('TODO(lewis6991): Support ranged signs') - insert(example_text) + insert(example_test3) feed 'gg' meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row = 2}) @@ -1865,8 +4711,7 @@ l5 end) it('can add multiple signs (multiple extmarks)', function() - pending('TODO(lewis6991): Support ranged signs') - insert(example_text) + insert(example_test3) feed'gg' meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'}) @@ -1884,21 +4729,19 @@ l5 {2:~ }| | ]]} - end) it('can add multiple signs (multiple extmarks) 2', function() - insert(example_text) + insert(example_test3) feed 'gg' - meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'}) - meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'}) - + meths.buf_set_extmark(0, ns, 3, -1, {sign_text='S1'}) + meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2', end_row = 3}) screen:expect{grid=[[ {1: }^l1 | - S2S1l2 | - {1: }l3 | - {1: }l4 | + S2{1: }l2 | + S2{1: }l3 | + S1S2l4 | {1: }l5 | {1: } | {2:~ }| @@ -1906,29 +4749,11 @@ l5 {2:~ }| | ]]} - - -- TODO(lewis6991): Support ranged signs - -- meths.buf_set_extmark(1, ns, 1, -1, {sign_text='S3', end_row = 2}) - - -- screen:expect{grid=[[ - -- {1: }^l1 | - -- S3S2S1l2 | - -- S3{1: }l3 | - -- {1: }l4 | - -- {1: }l5 | - -- {1: } | - -- {2:~ }| - -- {2:~ }| - -- {2:~ }| - -- | - -- ]]} - end) it('can add multiple signs (multiple extmarks) 3', function() - pending('TODO(lewis6991): Support ranged signs') - insert(example_text) + insert(example_test3) feed 'gg' meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1', end_row=2}) @@ -1937,7 +4762,7 @@ l5 screen:expect{grid=[[ {1: }^l1 | S1{1: }l2 | - S2S1l3 | + S1S2l3 | S2{1: }l4 | {1: }l5 | {1: } | @@ -1949,7 +4774,7 @@ l5 end) it('can add multiple signs (multiple extmarks) 4', function() - insert(example_text) + insert(example_test3) feed 'gg' meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1', end_row=0}) @@ -1970,7 +4795,7 @@ l5 end) it('works with old signs', function() - insert(example_text) + insert(example_test3) feed 'gg' helpers.command('sign define Oldsign text=x') @@ -1982,7 +4807,7 @@ l5 meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S5'}) screen:expect{grid=[[ - S4S1^l1 | + S1S4^l1 | x S2l2 | S5{1: }l3 | {1: }l4 | @@ -1996,8 +4821,7 @@ l5 end) it('works with old signs (with range)', function() - pending('TODO(lewis6991): Support ranged signs') - insert(example_text) + insert(example_test3) feed 'gg' helpers.command('sign define Oldsign text=x') @@ -2010,9 +4834,9 @@ l5 meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S5'}) screen:expect{grid=[[ - S3S4S1^l1 | - S2S3x l2 | - S5S3{1: }l3 | + S1S3S4^l1 | + x S2S3l2 | + S3S5{1: }l3 | S3{1: }l4 | S3{1: }l5 | {1: } | @@ -2024,9 +4848,7 @@ l5 end) it('can add a ranged sign (with start out of view)', function() - pending('TODO(lewis6991): Support ranged signs') - - insert(example_text) + insert(example_test3) command 'set signcolumn=yes:2' feed 'gg' feed '2<C-e>' @@ -2068,26 +4890,26 @@ l5 end screen:expect{grid=[[ - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | - X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:^h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} | + W X Y Z {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:^h} | | ]]} end) it('works with priority #19716', function() screen:try_resize(20, 3) - insert(example_text) + insert(example_test3) feed 'gg' - helpers.command('sign define Oldsign text=O3') - helpers.command([[exe 'sign place 42 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command('sign define Oldsign text=O3') + command([[exe 'sign place 42 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S4', priority=100}) meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S2', priority=5}) @@ -2101,7 +4923,7 @@ l5 ]]} -- Check truncation works too - meths.win_set_option(0, 'signcolumn', 'auto') + meths.set_option_value('signcolumn', 'auto', {}) screen:expect{grid=[[ S5^l1 | @@ -2109,6 +4931,52 @@ l5 | ]]} end) + + it('does not overflow with many old signs #23852', function() + screen:try_resize(20, 3) + + command('set signcolumn:auto:9') + command('sign define Oldsign text=O3') + command([[exe 'sign place 01 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command([[exe 'sign place 02 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command([[exe 'sign place 03 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command([[exe 'sign place 04 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command([[exe 'sign place 05 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command([[exe 'sign place 06 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command([[exe 'sign place 07 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command([[exe 'sign place 08 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + command([[exe 'sign place 09 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) + screen:expect{grid=[[ + O3O3O3O3O3O3O3O3O3^ | + {2:~ }| + | + ]]} + + meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1', priority=1}) + screen:expect_unchanged() + + meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S5', priority=200}) + screen:expect{grid=[[ + O3O3O3O3O3O3O3O3S5^ | + {2:~ }| + | + ]]} + + assert_alive() + end) + + it('does not set signcolumn for signs without text', function() + screen:try_resize(20, 3) + meths.set_option_value('signcolumn', 'auto', {}) + insert(example_test3) + feed 'gg' + meths.buf_set_extmark(0, ns, 0, -1, {number_hl_group='Error'}) + screen:expect{grid=[[ + ^l1 | + l2 | + | + ]]} + end) end) describe('decorations: virt_text', function() diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index dbdf3823ec..92b7235885 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -1251,6 +1251,98 @@ AAAB]] ]]} end) end) + + it('redraws with a change to non-current buffer', function() + write_file(fname, "aaa\nbbb\nccc\n\nxx", false) + write_file(fname_2, "aaa\nbbb\nccc\n\nyy", false) + reread() + local buf = meths.get_current_buf() + command('botright new') + screen:expect{grid=[[ + {1: }aaa │{1: }aaa | + {1: }bbb │{1: }bbb | + {1: }ccc │{1: }ccc | + {1: } │{1: } | + {1: }{8:xx}{9: }│{1: }{8:yy}{9: }| + {6:~ }│{6:~ }| + {3:<onal-diff-screen-1 <l-diff-screen-1.2 }| + ^ | + {6:~ }| + {6:~ }| + {6:~ }| + {6:~ }| + {6:~ }| + {6:~ }| + {7:[No Name] }| + :e | + ]]} + + meths.buf_set_lines(buf, 1, 2, true, {'BBB'}) + screen:expect{grid=[[ + {1: }aaa │{1: }aaa | + {1: }{8:BBB}{9: }│{1: }{8:bbb}{9: }| + {1: }ccc │{1: }ccc | + {1: } │{1: } | + {1: }{8:xx}{9: }│{1: }{8:yy}{9: }| + {6:~ }│{6:~ }| + {3:<-diff-screen-1 [+] <l-diff-screen-1.2 }| + ^ | + {6:~ }| + {6:~ }| + {6:~ }| + {6:~ }| + {6:~ }| + {6:~ }| + {7:[No Name] }| + :e | + ]]} + end) + + it('redraws with a change current buffer in another window', function() + write_file(fname, "aaa\nbbb\nccc\n\nxx", false) + write_file(fname_2, "aaa\nbbb\nccc\n\nyy", false) + reread() + local buf = meths.get_current_buf() + command('botright split | diffoff') + screen:expect{grid=[[ + {1: }aaa │{1: }aaa | + {1: }bbb │{1: }bbb | + {1: }ccc │{1: }ccc | + {1: } │{1: } | + {1: }{8:xx}{9: }│{1: }{8:yy}{9: }| + {6:~ }│{6:~ }| + {3:<onal-diff-screen-1 <l-diff-screen-1.2 }| + ^aaa | + bbb | + ccc | + | + xx | + {6:~ }| + {6:~ }| + {7:Xtest-functional-diff-screen-1 }| + :e | + ]]} + + meths.buf_set_lines(buf, 1, 2, true, {'BBB'}) + screen:expect{grid=[[ + {1: }aaa │{1: }aaa | + {1: }{8:BBB}{9: }│{1: }{8:bbb}{9: }| + {1: }ccc │{1: }ccc | + {1: } │{1: } | + {1: }{8:xx}{9: }│{1: }{8:yy}{9: }| + {6:~ }│{6:~ }| + {3:<-diff-screen-1 [+] <l-diff-screen-1.2 }| + ^aaa | + BBB | + ccc | + | + xx | + {6:~ }| + {6:~ }| + {7:Xtest-functional-diff-screen-1 [+] }| + :e | + ]]} + end) end) it('win_update redraws lines properly', function() @@ -1325,6 +1417,7 @@ it('win_update redraws lines properly', function() ]]} end) +-- oldtest: Test_diff_rnu() it('diff updates line numbers below filler lines', function() clear() local screen = Screen.new(40, 14) @@ -1401,6 +1494,7 @@ it('diff updates line numbers below filler lines', function() ]]) end) +-- oldtest: Test_diff_with_scroll_and_change() it('Align the filler lines when changing text in diff mode', function() clear() local screen = Screen.new(40, 20) diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua index cd2b48213d..9729f65355 100644 --- a/test/functional/ui/embed_spec.lua +++ b/test/functional/ui/embed_spec.lua @@ -5,7 +5,12 @@ local Screen = require('test.functional.ui.screen') local feed = helpers.feed local eq = helpers.eq +local neq = helpers.neq local clear = helpers.clear +local ok = helpers.ok +local funcs = helpers.funcs +local nvim_prog = helpers.nvim_prog +local retry = helpers.retry local function test_embed(ext_linegrid) local screen @@ -98,6 +103,7 @@ describe('--embed UI', function() -- attach immediately after startup, for early UI local screen = Screen.new(40, 8) + screen.rpc_async = true -- Avoid hanging. #24888 screen:attach {stdin_fd=3} screen:set_default_attr_ids { [1] = {bold = true, foreground = Screen.colors.Blue1}; @@ -132,3 +138,50 @@ describe('--embed UI', function() ]]} end) end) + +describe('--embed --listen UI', function() + it('waits for connection on listening address', function() + helpers.skip(helpers.is_os('win')) + clear() + local child_server = assert(helpers.new_pipename()) + funcs.jobstart({nvim_prog, '--embed', '--listen', child_server, '--clean'}) + retry(nil, nil, function() neq(nil, uv.fs_stat(child_server)) end) + + local child_session = helpers.connect(child_server) + + local info_ok, api_info = child_session:request('nvim_get_api_info') + ok(info_ok) + eq(2, #api_info) + ok(api_info[1] > 2, 'channel_id > 2', api_info[1]) + + child_session:request('nvim_exec2', [[ + let g:evs = [] + autocmd UIEnter * call add(g:evs, $"UIEnter:{v:event.chan}") + autocmd VimEnter * call add(g:evs, "VimEnter") + ]], {}) + + -- VimEnter and UIEnter shouldn't be triggered until after attach + local var_ok, var = child_session:request('nvim_get_var', 'evs') + ok(var_ok) + eq({}, var) + + local child_screen = Screen.new(40, 6) + child_screen:attach(nil, child_session) + child_screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] 0,0-1 All}| + | + ]], attr_ids={ + [1] = {foreground = Screen.colors.Blue, bold = true}; + [2] = {reverse = true, bold = true}; + }} + + -- VimEnter and UIEnter should now be triggered + var_ok, var = child_session:request('nvim_get_var', 'evs') + ok(var_ok) + eq({'VimEnter', ('UIEnter:%d'):format(api_info[1])}, var) + end) +end) diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 6759510ad1..2902b4a4a5 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -9,6 +9,7 @@ local eval = helpers.eval local eq = helpers.eq local neq = helpers.neq local expect = helpers.expect +local exec = helpers.exec local exec_lua = helpers.exec_lua local insert = helpers.insert local meths = helpers.meths @@ -65,20 +66,20 @@ describe('float window', function() it('closed immediately by autocmd #11383', function() eq('Window was closed immediately', pcall_err(exec_lua, [[ - local a = vim.api + local api = vim.api local function crashes(contents) - local buf = a.nvim_create_buf(false, true) - local floatwin = a.nvim_open_win(buf, true, { + local buf = api.nvim_create_buf(false, true) + local floatwin = api.nvim_open_win(buf, true, { relative = 'cursor'; style = 'minimal'; row = 0; col = 0; height = #contents; width = 10; }) - a.nvim_buf_set_lines(buf, 0, -1, true, contents) + api.nvim_buf_set_lines(buf, 0, -1, true, contents) local winnr = vim.fn.win_id2win(floatwin) - a.nvim_command('wincmd p') - a.nvim_command('autocmd CursorMoved * ++once '..winnr..'wincmd c') + api.nvim_command('wincmd p') + api.nvim_command('autocmd BufEnter * ++once '..winnr..'wincmd c') return buf, floatwin end crashes{'foo'} @@ -102,9 +103,32 @@ describe('float window', function() assert_alive() end) + it('open with WinNew autocmd', function() + local res = exec_lua([[ + local triggerd = false + local buf = vim.api.nvim_create_buf(true, true) + vim.api.nvim_create_autocmd('WinNew', { + callback = function(opt) + if opt.buf == buf then + triggerd = true + end + end + }) + local opts = { + relative = "win", + row = 0, col = 0, + width = 1, height = 1, + noautocmd = false, + } + vim.api.nvim_open_win(buf, true, opts) + return triggerd + ]]) + eq(true, res) + end) + it('opened with correct height', function() local height = exec_lua([[ - vim.api.nvim_set_option("winheight", 20) + vim.go.winheight = 20 local bufnr = vim.api.nvim_create_buf(false, true) local opts = { @@ -126,7 +150,7 @@ describe('float window', function() it('opened with correct width', function() local width = exec_lua([[ - vim.api.nvim_set_option("winwidth", 20) + vim.go.winwidth = 20 local bufnr = vim.api.nvim_create_buf(false, true) local opts = { @@ -414,6 +438,46 @@ describe('float window', function() eq(winids, eval('winids')) end) + it("open does not trigger BufEnter #15300", function() + local res = exec_lua[[ + local times = {} + local buf = vim.api.nvim_create_buf(fasle, true) + vim.api.nvim_create_autocmd('BufEnter', { + callback = function(opt) + if opt.buf == buf then + times[#times + 1] = 1 + end + end + }) + local win_id + local fconfig = { + relative = 'editor', + row = 10, + col = 10, + width = 10, + height = 10, + } + --enter is false doesn't trigger + win_id = vim.api.nvim_open_win(buf, false, fconfig) + vim.api.nvim_win_close(win_id, true) + times[#times + 1] = #times == 0 and true or nil + + --enter is true trigger + win_id = vim.api.nvim_open_win(buf, true, fconfig) + vim.api.nvim_win_close(win_id, true) + times[#times + 1] = #times == 2 and true or nil + + --enter is true and fconfig.noautocmd is true doesn't trigger + fconfig.noautocmd = true + win_id = vim.api.nvim_open_win(buf, true, fconfig) + vim.api.nvim_win_close(win_id, true) + times[#times + 1] = #times == 2 and true or nil + + return times + ]] + eq({true, 1, true}, res) + end) + it('no crash with bufpos and non-existent window', function() command('new') local closed_win = meths.get_current_win().id @@ -426,17 +490,57 @@ describe('float window', function() it("no segfault when setting minimal style after clearing local 'fillchars' #19510", function() local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1} local float_win = meths.open_win(0, true, float_opts) - meths.win_set_option(float_win, 'fillchars', NIL) + meths.set_option_value('fillchars', NIL, {win=float_win.id}) float_opts.style = 'minimal' meths.win_set_config(float_win, float_opts) assert_alive() + end) + + it("should re-apply 'style' when present", function() + local float_opts = {style = 'minimal', relative = 'editor', row = 1, col = 1, width = 1, height = 1} + local float_win = meths.open_win(0, true, float_opts) + meths.set_option_value('number', true, { win = float_win }) + float_opts.row = 2 + meths.win_set_config(float_win, float_opts) + eq(false, meths.get_option_value('number', { win = float_win })) + end) + + it("should not re-apply 'style' when missing", function() + local float_opts = {style = 'minimal', relative = 'editor', row = 1, col = 1, width = 1, height = 1} + local float_win = meths.open_win(0, true, float_opts) + meths.set_option_value('number', true, { win = float_win }) + float_opts.row = 2 + float_opts.style = nil + meths.win_set_config(float_win, float_opts) + eq(true, meths.get_option_value('number', { win = float_win })) end) it("'scroll' is computed correctly when opening float with splitkeep=screen #20684", function() - meths.set_option('splitkeep', 'screen') + meths.set_option_value('splitkeep', 'screen', {}) local float_opts = {relative = 'editor', row = 1, col = 1, width = 10, height = 10} local float_win = meths.open_win(0, true, float_opts) - eq(5, meths.win_get_option(float_win, 'scroll')) + eq(5, meths.get_option_value('scroll', {win=float_win.id})) + end) + + it(':unhide works when there are floating windows', function() + local float_opts = {relative = 'editor', row = 1, col = 1, width = 5, height = 5} + local w0 = curwin() + meths.open_win(0, false, float_opts) + meths.open_win(0, false, float_opts) + eq(3, #meths.list_wins()) + command('unhide') + eq({ w0 }, meths.list_wins()) + end) + + it(':all works when there are floating windows', function() + command('args Xa.txt') + local float_opts = {relative = 'editor', row = 1, col = 1, width = 5, height = 5} + local w0 = curwin() + meths.open_win(0, false, float_opts) + meths.open_win(0, false, float_opts) + eq(3, #meths.list_wins()) + command('all') + eq({ w0 }, meths.list_wins()) end) describe('with only one tabpage,', function() @@ -738,7 +842,7 @@ describe('float window', function() [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}, + [7] = {foreground = Screen.colors.White, 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}, @@ -879,6 +983,71 @@ describe('float window', function() end end) + it('window position fixed', function() + command('rightbelow 20vsplit') + local buf = meths.create_buf(false,false) + local win = meths.open_win(buf, false, { + relative='win', width=15, height=2, row=2, col=10, anchor='NW', fixed=true}) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + {5:[No Name] }{4:[No Name] }| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 5 + {1: }| + {2:~ }| + ]], float_pos={ + [5] = {{id = 1002}, "NW", 4, 2, 10, true}; + }} + else + screen:expect([[ + {5:│}^ | + {0:~ }{5:│}{0:~ }| + {0:~ }{5:│}{0:~ }{1: }| + {0:~ }{5:│}{0:~ }{2:~ }| + {0:~ }{5:│}{0:~ }| + {5:[No Name] }{4:[No Name] }| + | + ]]) + end + + meths.win_set_config(win, {fixed=false}) + + if multigrid then + screen:expect_unchanged() + else + screen:expect([[ + {5:│}^ | + {0:~ }{5:│}{0:~ }| + {0:~ }{5:│}{0:~ }{1: }| + {0:~ }{5:│}{0:~ }{2:~ }| + {0:~ }{5:│}{0:~ }| + {5:[No Name] }{4:[No Name] }| + | + ]]) + end + end) + it('draws correctly with redrawdebug=compositor', function() -- NB: we do not test that it produces the "correct" debug info -- (as it is intermediate only, and is allowed to change by internal @@ -1003,14 +1172,14 @@ describe('float window', function() it('return their configuration', function() local buf = meths.create_buf(false, false) local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5, zindex=60}) - local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20, zindex=60} + local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false} eq(expected, meths.win_get_config(win)) - eq({relative='', external=false, focusable=true}, meths.win_get_config(0)) + eq({relative='', external=false, focusable=true, hide=false}, meths.win_get_config(0)) if multigrid then meths.win_set_config(win, {external=true, width=10, height=1}) - eq({external=true,focusable=true,width=10,height=1,relative=''}, meths.win_get_config(win)) + eq({external=true,focusable=true,width=10,height=1,relative='',hide=false}, meths.win_get_config(win)) end end) @@ -1425,16 +1594,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:╔═════════╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1468,16 +1637,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:┌─────────┐}| {5:│}{1: halloj! }{5:│}| {5:│}{1: BORDAA }{5:│}| {5:└─────────┘}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1511,16 +1680,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:╭─────────╮}| {5:│}{1: halloj! }{5:│}| {5:│}{1: BORDAA }{5:│}| {5:╰─────────╯}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1554,16 +1723,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5: }| {5: }{1: halloj! }{5: }| {5: }{1: BORDAA }{5: }| {5: }| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1598,16 +1767,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:x}{7:ååååååååå}{5:\}| {17:n̈̊}{1: halloj! }{17:n̈̊}| {17:n̈̊}{1: BORDAA }{17:n̈̊}| {5:\}{7:ååååååååå}{5:x}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1641,14 +1810,14 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1: halloj! }| {1: BORDAA }| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1682,14 +1851,14 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:<}{1: halloj! }{5:>}| {5:<}{1: BORDAA }{5:>}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1723,16 +1892,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:_________}| {1: halloj! }| {1: BORDAA }| {5:---------}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1774,15 +1943,15 @@ describe('float window', function() ^ | ## grid 3 | - ## grid 5 + ## grid 4 {1: halloj! }{25: }| {1: BORDAA }{26: }| {25: }{26: }| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0, linecount = 6}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0, linecount = 6, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1831,6 +2000,94 @@ describe('float window', function() eq('center', title_pos) end) + it('validates footer footer_pos', function() + local buf = meths.create_buf(false,false) + eq("footer requires border to be set", + pcall_err(meths.open_win,buf, false, { + relative='editor', width=9, height=2, row=2, col=5, footer='Footer', + })) + eq("footer_pos requires footer to be set", + pcall_err(meths.open_win,buf, false, { + relative='editor', width=9, height=2, row=2, col=5, + border='single', footer_pos='left', + })) + end) + + it('validate footer_pos in nvim_win_get_config', function() + local footer_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', + footer = 'Test', + footer_pos = 'center' + } + + local win_id = vim.api.nvim_open_win(bufnr, true, opts) + return vim.api.nvim_win_get_config(win_id).footer_pos + ]]) + + eq('center', footer_pos) + end) + + it('center aligned title longer than window width #25746', 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 = "abcdefghijklmnopqrstuvwxyz",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 4 + {5:╔}{11:abcdefghi}{5:╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚═════════╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔}{11:abcdefghi}{5:╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚═════════╝}{0: }| + | + ]]} + end + + meths.win_close(win, false) + assert_alive() + end) it('border with title', function() local buf = meths.create_buf(false, false) @@ -1860,16 +2117,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:╔}{11:Left}{5:═════╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1903,16 +2160,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:╔═}{11:Center}{5:══╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1946,16 +2203,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:╔════}{11:Right}{5:╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1989,16 +2246,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:╔═════}🦄BB{5:╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -2013,9 +2270,376 @@ describe('float window', function() end end) + it('border with footer', 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", + footer = "Left",footer_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 4 + {5:╔═════════╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚}{11:Left}{5:═════╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔═════════╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚}{11:Left}{5:═════╝}{0: }| + | + ]]} + end + + meths.win_set_config(win, {footer= "Center",footer_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 4 + {5:╔═════════╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚═}{11:Center}{5:══╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔═════════╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚═}{11:Center}{5:══╝}{0: }| + | + ]]} + end + + meths.win_set_config(win, {footer= "Right",footer_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 4 + {5:╔═════════╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚════}{11:Right}{5:╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔═════════╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚════}{11:Right}{5:╝}{0: }| + | + ]]} + end + + meths.win_set_config(win, {footer= { {"🦄"},{"BB"}},footer_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 4 + {5:╔═════════╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚═════}🦄BB{5:╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔═════════╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚═════}🦄BB{5:╝}{0: }| + | + ]]} + end + end) + + it('border with title and footer', 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", footer = "Right", footer_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 4 + {5:╔}{11:Left}{5:═════╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚════}{11:Right}{5:╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + 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:╚════}{11:Right}{5:╝}{0: }| + | + ]]} + end + + meths.win_set_config(win, {title= "Center",title_pos="center",footer= "Center",footer_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 4 + {5:╔═}{11:Center}{5:══╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚═}{11:Center}{5:══╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + 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:╚═}{11:Center}{5:══╝}{0: }| + | + ]]} + end + + meths.win_set_config(win, {title= "Right",title_pos="right",footer= "Left",footer_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 4 + {5:╔════}{11:Right}{5:╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚}{11:Left}{5:═════╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + 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:╚}{11:Left}{5:═════╝}{0: }| + | + ]]} + end + + command('hi B0 guibg=Red guifg=Black') + command('hi B1 guifg=White') + meths.win_set_config(win, { + title = {{"🦄"}, {"BB", {"B0", "B1"}}}, title_pos = "right", + footer= {{"🦄"}, {"BB", {"B0", "B1"}}}, footer_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 4 + {5:╔═════}🦄{7:BB}{5:╗}| + {5:║}{1: halloj! }{5:║}| + {5:║}{1: BORDAA }{5:║}| + {5:╚═════}🦄{7:BB}{5:╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔═════}🦄{7:BB}{5:╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚═════}🦄{7:BB}{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"}) + meths.open_win(buf, false, {relative='editor', width=40, height=7, row=0, col=0, border="single", zindex=201}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -2046,10 +2670,10 @@ describe('float window', function() {5:│}{2:~ }{5:│}| {5:└────────────────────────────────────────┘}| ]], float_pos={ - [4] = { { id = 1001 }, "NW", 1, 0, 0, true } + [4] = { { id = 1001 }, "NW", 1, 0, 0, true, 201 } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -2058,8 +2682,8 @@ describe('float window', function() {5:│}{2:~ }{5:│}| {5:│}{2:~ }{5:│}| {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| {5:└──────────────────────────────────────┘}| - | ]]} end end) @@ -2097,17 +2721,17 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:╔═════════╗}| {5:║}{1:aaa aab }{5:║}| {5:║}{1:abb acc }{5:║}| {5:║}{1:^ }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 0, 5, true } + [4] = { { id = 1001 }, "NW", 1, 0, 5, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 2, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -2150,23 +2774,23 @@ describe('float window', function() {0:~ }| ## grid 3 {3:-- }{8:match 1 of 4} | - ## grid 5 + ## grid 4 {5:╔═════════╗}| {5:║}{1:aaa aab }{5:║}| {5:║}{1:abb acc }{5:║}| {5:║}{1:acc^ }{5:║}| {5:╚═════════╝}| - ## grid 6 + ## grid 5 {1: aaa }| {1: aab }| {1: abb }| {13: acc }| ]], float_pos={ - [5] = { { id = 1002 }, "NW", 1, 0, 5, true, 50 }, - [6] = { { id = -1 }, "NW", 5, 4, 0, false, 100 } + [4] = { { id = 1001 }, "NW", 1, 0, 5, true, 50 }; + [5] = { { id = -1 }, "NW", 4, 4, 0, false, 100 }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3, linecount=3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 2, curcol = 3, linecount=3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -2182,6 +2806,374 @@ describe('float window', function() {3:-- }{8:match 1 of 4} | ]]} end + + feed '<esc>' + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {5:╔═════════╗}| + {5:║}{1:aaa aab }{5:║}| + {5:║}{1:abb acc }{5:║}| + {5:║}{1:ac^c }{5:║}| + {5:╚═════════╝}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 0, 5, true }; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 2, curcol = 2, linecount = 3, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {5:╔═════════╗} | + {0:~ }{5:║}{1:aaa aab }{5:║}{0: }| + {0:~ }{5:║}{1:abb acc }{5:║}{0: }| + {0:~ }{5:║}{1:ac^c }{5:║}{0: }| + {0:~ }{5:╚═════════╝}{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end + + exec([[ + nnoremenu Test.foo : + nnoremenu Test.bar : + nnoremenu Test.baz : + ]]) + feed ':popup Test<CR>' + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :popup Test | + ## grid 4 + {5:╔═════════╗}| + {5:║}{1:aaa aab }{5:║}| + {5:║}{1:abb acc }{5:║}| + {5:║}{1:ac^c }{5:║}| + {5:╚═════════╝}| + ## grid 5 + {1: foo }| + {1: bar }| + {1: baz }| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 0, 5, true }; + [5] = { { id = -1 }, "NW", 4, 4, 2, false, 250 }; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 2, curcol = 2, linecount = 3, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {5:╔═════════╗} | + {0:~ }{5:║}{1:aaa aab }{5:║}{0: }| + {0:~ }{5:║}{1:abb acc }{5:║}{0: }| + {0:~ }{5:║}{1:ac^c }{5:║}{0: }| + {0:~ }{5:╚═}{1: foo }{5:═══╝}{0: }| + {0:~ }{1: bar }{0: }| + {0:~ }{1: baz }{0: }| + {0:~ }| + {0:~ }| + :popup Test | + ]]} + end + end) + + it('show ruler of current floating window', function() + command 'set ruler' + local buf = meths.create_buf(false, false) + meths.buf_set_lines(buf, 0, -1, true, {'aaa aab ', + 'abb acc '}) + meths.open_win(buf, true, {relative='editor', width=9, height=3, row=0, col=5}) + feed 'gg' + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + 1,1 All | + ## grid 4 + {1:^aaa aab }| + {1:abb acc }| + {2:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {1:^aaa aab } | + {0:~ }{1:abb acc }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + 1,1 All | + ]]} + end + + feed 'w' + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + 1,5 All | + ## grid 4 + {1:aaa ^aab }| + {1:abb acc }| + {2:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 4, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {1:aaa ^aab } | + {0:~ }{1:abb acc }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + 1,5 All | + ]]} + end + end) + + it("correct ruler position in current float with 'rulerformat' set", function() + command 'set ruler rulerformat=fish:<><' + meths.open_win(0, true, {relative='editor', width=9, height=3, row=0, col=5}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + fish:<>< | + ## grid 4 + {1:^ }| + {2:~ }| + {2:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {1:^ } | + {0:~ }{2:~ }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + fish:<>< | + ]]} + end + end) + + it('does not show ruler of not-last current float during ins-completion', function() + screen:try_resize(50,9) + command 'set ruler showmode' + meths.open_win(0, false, {relative='editor', width=3, height=3, row=0, col=0}) + meths.open_win(0, false, {relative='editor', width=3, height=3, row=0, col=5}) + feed '<c-w>w' + neq('', meths.win_get_config(0).relative) + neq(funcs.winnr '$', funcs.winnr()) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [3:--------------------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + 0,0-1 All | + ## grid 4 + {1: }| + {2:~ }| + {2:~ }| + ## grid 5 + {1:^ }| + {2:~ }| + {2:~ }| + ]], float_pos={ + [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 0, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {1: } {1:^ } | + {2:~ }{0: }{2:~ }{0: }| + {2:~ }{0: }{2:~ }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + 0,0-1 All | + ]]} + end + feed 'i<c-x>' + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [3:--------------------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | + ## grid 4 + {1: }| + {2:~ }| + {2:~ }| + ## grid 5 + {1:^ }| + {2:~ }| + {2:~ }| + ]], float_pos={ + [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 0, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {1: } {1:^ } | + {2:~ }{0: }{2:~ }{0: }| + {2:~ }{0: }{2:~ }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | + ]]} + end end) it('can have minimum size', function() @@ -2208,10 +3200,10 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:x}| ]], float_pos={ - [5] = {{id = 1002}, "NW", 2, 0, 4, false} + [4] = {{id = 1001}, "NW", 2, 0, 4, false} }} else screen:expect([[ @@ -2245,10 +3237,10 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:x}| ]], float_pos={ - [5] = {{id = 1002}, "NW", 2, 0, 15, false} + [4] = {{id = 1001}, "NW", 2, 0, 15, false} }} else screen:expect([[ @@ -2296,6 +3288,154 @@ describe('float window', function() end end) + describe('no crash when rearranging windows', function() + local function test_rearrange_windows(cmd) + command('set laststatus=2') + screen:try_resize(40, 13) + + command('args X1 X2 X3 X4 X5 X6') + command('sargument 2') + command('sargument 3') + local w3 = curwin() + command('sargument 4') + local w4 = curwin() + command('sargument 5') + command('sargument 6') + + local float_opts = { relative = 'editor', row = 6, col = 0, width = 40, height = 1 } + meths.win_set_config(w3, float_opts) + meths.win_set_config(w4, float_opts) + command('wincmd =') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [8:----------------------------------------]| + [8:----------------------------------------]| + {4:X6 }| + [7:----------------------------------------]| + [7:----------------------------------------]| + {5:X5 }| + [4:----------------------------------------]| + [4:----------------------------------------]| + {5:X2 }| + [2:----------------------------------------]| + [2:----------------------------------------]| + {5:X1 }| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + ## grid 3 + | + ## grid 4 + | + {0:~ }| + ## grid 5 + {1: }| + ## grid 6 + {1: }| + ## grid 7 + | + {0:~ }| + ## grid 8 + ^ | + {0:~ }| + ]], float_pos={ + [5] = {{id = 1002}, "NW", 1, 6, 0, true, 50}; + [6] = {{id = 1003}, "NW", 1, 6, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [7] = {win = {id = 1004}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [8] = {win = {id = 1005}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {4:X6 }| + | + {0:~ }| + {5:X5 }| + {1: }| + {0:~ }| + {5:X2 }| + | + {0:~ }| + {5:X1 }| + | + ]]} + end + + command(cmd) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + {4:X1 }| + [4:----------------------------------------]| + {5:X2 }| + [9:----------------------------------------]| + {5:X3 }| + [10:----------------------------------------]| + {5:X4 }| + [7:----------------------------------------]| + {5:X5 }| + [8:----------------------------------------]| + {5:X6 }| + [3:----------------------------------------]| + ## grid 2 + ^ | + ## grid 3 + | + ## grid 4 + | + ## grid 7 + | + ## grid 8 + | + ## grid 9 + | + ## grid 10 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [7] = {win = {id = 1004}, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [8] = {win = {id = 1005}, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [9] = {win = {id = 1006}, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [10] = {win = {id = 1007}, topline = 0, botline = 1, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {4:X1 }| + | + {5:X2 }| + | + {5:X3 }| + | + {5:X4 }| + | + {5:X5 }| + | + {5:X6 }| + | + ]]} + end + end + + it('using :unhide', function() + test_rearrange_windows('unhide') + end) + + it('using :all', function() + test_rearrange_windows('all') + end) + end) + it('API has proper error messages', function() local buf = meths.create_buf(false,false) eq("Invalid key: 'bork'", @@ -2496,7 +3636,6 @@ describe('float window', function() ]]) end - meths.win_set_config(win, {relative='win', win=oldwin, row=1, col=10, anchor='NW'}) if multigrid then screen:expect{grid=[[ @@ -2618,7 +3757,8 @@ describe('float window', function() curline = 0, curcol = 3, linecount = 2, - win = { id = 1000 } + sum_scroll_delta = 0, + win = { id = 1000 }, }, [4] = { topline = 0, @@ -2626,6 +3766,7 @@ describe('float window', function() curline = 0, curcol = 3, linecount = 2, + sum_scroll_delta = 0, win = { id = 1001 } }, [5] = { @@ -2634,6 +3775,7 @@ describe('float window', function() curline = 0, curcol = 0, linecount = 1, + sum_scroll_delta = 0, win = { id = 1002 } } }} @@ -2741,13 +3883,13 @@ describe('float window', function() {0:~ }| {0:~ }| {0:~ }| - ## grid 6 + ## grid 5 {5:╔═════════╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [6] = {{id = 1003}, "NW", 4, 1, 14, true} + [5] = {{id = 1002}, "NW", 4, 1, 14, true} }} else screen:expect([[ @@ -2798,13 +3940,13 @@ describe('float window', function() {0:~ }| {0:~ }| {0:~ }| - ## grid 6 + ## grid 5 {5:╔═════════╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [6] = {{id = 1003}, "NE", 4, 0, 14, true} + [5] = {{id = 1002}, "NE", 4, 0, 14, true} }} else screen:expect([[ @@ -2855,13 +3997,13 @@ describe('float window', function() {0:~ }| {0:~ }| {0:~ }| - ## grid 6 + ## grid 5 {5:╔═════════╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [6] = {{id = 1003}, "SE", 4, 1, 14, true} + [5] = {{id = 1002}, "SE", 4, 1, 14, true} }} else screen:expect([[ @@ -2912,13 +4054,13 @@ describe('float window', function() {0:~ }| {0:~ }| {0:~ }| - ## grid 6 + ## grid 5 {5:╔═════════╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| ]], float_pos={ - [6] = {{id = 1003}, "SW", 4, 0, 14, true} + [5] = {{id = 1002}, "SW", 4, 0, 14, true} }} else screen:expect([[ @@ -2939,6 +4081,198 @@ describe('float window', function() end end) + it('anchored to another floating window updated in the same call #14735', function() + feed('i<CR><CR><CR><Esc>') + + exec([[ + let b1 = nvim_create_buf(v:true, v:false) + let b2 = nvim_create_buf(v:true, v:false) + let b3 = nvim_create_buf(v:true, v:false) + let b4 = nvim_create_buf(v:true, v:false) + let b5 = nvim_create_buf(v:true, v:false) + let b6 = nvim_create_buf(v:true, v:false) + let b7 = nvim_create_buf(v:true, v:false) + let b8 = nvim_create_buf(v:true, v:false) + call setbufline(b1, 1, '1') + call setbufline(b2, 1, '2') + call setbufline(b3, 1, '3') + call setbufline(b4, 1, '4') + call setbufline(b5, 1, '5') + call setbufline(b6, 1, '6') + call setbufline(b7, 1, '7') + call setbufline(b8, 1, '8') + let o1 = #{relative: 'editor', row: 1, col: 10, width: 5, height: 1} + let w1 = nvim_open_win(b1, v:false, o1) + let o2 = extendnew(o1, #{col: 30}) + let w2 = nvim_open_win(b2, v:false, o2) + let o3 = extendnew(o1, #{relative: 'win', win: w1, anchor: 'NE', col: 0}) + let w3 = nvim_open_win(b3, v:false, o3) + let o4 = extendnew(o3, #{win: w2}) + let w4 = nvim_open_win(b4, v:false, o4) + let o5 = extendnew(o3, #{win: w3, anchor: 'SE', row: 0}) + let w5 = nvim_open_win(b5, v:false, o5) + let o6 = extendnew(o5, #{win: w4}) + let w6 = nvim_open_win(b6, v:false, o6) + let o7 = extendnew(o5, #{win: w5, anchor: 'SW', col: 5}) + let w7 = nvim_open_win(b7, v:false, o7) + let o8 = extendnew(o7, #{win: w6}) + let w8 = nvim_open_win(b8, v:false, o8) + ]]) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + | + | + ^ | + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {1:1 }| + ## grid 6 + {1:2 }| + ## grid 7 + {1:3 }| + ## grid 8 + {1:4 }| + ## grid 9 + {1:5 }| + ## grid 10 + {1:6 }| + ## grid 11 + {1:7 }| + ## grid 12 + {1:8 }| + ]], float_pos={ + [5] = {{id = 1002}, "NW", 1, 1, 10, true, 50}; + [6] = {{id = 1003}, "NW", 1, 1, 30, true, 50}; + [7] = {{id = 1004}, "NE", 5, 1, 0, true, 50}; + [8] = {{id = 1005}, "NE", 6, 1, 0, true, 50}; + [9] = {{id = 1006}, "SE", 7, 0, 0, true, 50}; + [10] = {{id = 1007}, "SE", 8, 0, 0, true, 50}; + [11] = {{id = 1008}, "SW", 9, 0, 5, true, 50}; + [12] = {{id = 1009}, "SW", 10, 0, 5, true, 50}; + }} + else + screen:expect([[ + {1:7 } {1:8 } | + {1:5 } {1:1 } {1:6 } {1:2 } | + {1:3 } {1:4 } | + ^ | + {0:~ }| + {0:~ }| + | + ]]) + end + + -- Reconfigure in different directions + exec([[ + let o1 = extendnew(o1, #{anchor: 'NW'}) + call nvim_win_set_config(w8, o1) + let o2 = extendnew(o2, #{anchor: 'NW'}) + call nvim_win_set_config(w4, o2) + let o3 = extendnew(o3, #{win: w8}) + call nvim_win_set_config(w2, o3) + let o4 = extendnew(o4, #{win: w4}) + call nvim_win_set_config(w1, o4) + let o5 = extendnew(o5, #{win: w2}) + call nvim_win_set_config(w6, o5) + let o6 = extendnew(o6, #{win: w1}) + call nvim_win_set_config(w3, o6) + let o7 = extendnew(o7, #{win: w6}) + call nvim_win_set_config(w5, o7) + let o8 = extendnew(o8, #{win: w3}) + call nvim_win_set_config(w7, o8) + ]]) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + | + | + ^ | + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {1:1 }| + ## grid 6 + {1:2 }| + ## grid 7 + {1:3 }| + ## grid 8 + {1:4 }| + ## grid 9 + {1:5 }| + ## grid 10 + {1:6 }| + ## grid 11 + {1:7 }| + ## grid 12 + {1:8 }| + ]], float_pos={ + [5] = {{id = 1002}, "NE", 8, 1, 0, true, 50}; + [6] = {{id = 1003}, "NE", 12, 1, 0, true, 50}; + [7] = {{id = 1004}, "SE", 5, 0, 0, true, 50}; + [8] = {{id = 1005}, "NW", 1, 1, 30, true, 50}; + [9] = {{id = 1006}, "SW", 10, 0, 5, true, 50}; + [10] = {{id = 1007}, "SE", 6, 0, 0, true, 50}; + [11] = {{id = 1008}, "SW", 7, 0, 5, true, 50}; + [12] = {{id = 1009}, "NW", 1, 1, 10, true, 50}; + }} + else + screen:expect([[ + {1:5 } {1:7 } | + {1:6 } {1:8 } {1:3 } {1:4 } | + {1:2 } {1:1 } | + ^ | + {0:~ }| + {0:~ }| + | + ]]) + end + + -- Not clear how cycles should behave, but they should not hang or crash + exec([[ + let o1 = extendnew(o1, #{relative: 'win', win: w7}) + call nvim_win_set_config(w1, o1) + let o2 = extendnew(o2, #{relative: 'win', win: w8}) + call nvim_win_set_config(w2, o2) + let o3 = extendnew(o3, #{win: w1}) + call nvim_win_set_config(w3, o3) + let o4 = extendnew(o4, #{win: w2}) + call nvim_win_set_config(w4, o4) + let o5 = extendnew(o5, #{win: w3}) + call nvim_win_set_config(w5, o5) + let o6 = extendnew(o6, #{win: w4}) + call nvim_win_set_config(w6, o6) + let o7 = extendnew(o7, #{win: w5}) + call nvim_win_set_config(w7, o7) + let o8 = extendnew(o8, #{win: w6}) + call nvim_win_set_config(w8, o8) + redraw + ]]) + end) + it('can be placed relative text in a window', function() screen:try_resize(30,5) local firstwin = meths.get_current_win().id @@ -2988,12 +4322,10 @@ describe('float window', function() | ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 2, 3, 2, true } + [4] = { { id = 1001 }, "NW", 2, 3, 2, true } }} else screen:expect{grid=[[ @@ -3004,7 +4336,7 @@ describe('float window', function() | ]]} end - eq({relative='win', width=12, height=1, bufpos={1,32}, anchor='NW', + eq({relative='win', width=12, height=1, bufpos={1,32}, anchor='NW', hide=false, external=false, col=0, row=1, win=firstwin, focusable=true, zindex=50}, meths.win_get_config(win)) feed('<c-e>') @@ -3023,12 +4355,10 @@ describe('float window', function() | ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 2, 2, 2, true } + [4] = { { id = 1001 }, "NW", 2, 2, 2, true }, }} else screen:expect{grid=[[ @@ -3057,12 +4387,10 @@ describe('float window', function() more text | ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 2, 1, 32, true } + [4] = { { id = 1001 }, "NW", 2, 1, 32, true } }} else -- note: appears misaligned due to cursor @@ -3101,12 +4429,10 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 2, 2, 7, true } + [4] = { { id = 1001 }, "NW", 2, 2, 7, true } }} else screen:expect{grid=[[ @@ -3149,12 +4475,10 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| ]], float_pos={ - [5] = { { - id = 1002 - }, "SW", 2, 1, 7, true } + [4] = { { id = 1001 }, "SW", 2, 1, 7, true } }} else screen:expect{grid=[[ @@ -3176,15 +4500,15 @@ describe('float window', function() 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:--------------------]| + [2:----]{5:│}[5:--------------------]| + [2:----]{5:│}[5:--------------------]| + [2:----]{5:│}[5:--------------------]| + [2:----]{5:│}[5:--------------------]| + [2:----]{5:│}[5:--------------------]| + [2:----]{5:│}[5:--------------------]| + [2:----]{5:│}[5:--------------------]| + [2:----]{5:│}[5:--------------------]| + [2:----]{5:│}[5:--------------------]| [3:-------------------------]| ## grid 2 exam| @@ -3198,9 +4522,9 @@ describe('float window', function() the | ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| - ## grid 6 + ## grid 5 ^ | {0:~ }| {0:~ }| @@ -3211,9 +4535,7 @@ describe('float window', function() {0:~ }| {0:~ }| ]], float_pos={ - [5] = { { - id = 1002 - }, "SW", 2, 8, 0, true } + [4] = { { id = 1001 }, "SW", 2, 8, 0, true } }} else screen:expect{grid=[[ @@ -3257,12 +4579,10 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 2, 2, 5, true } + [4] = { { id = 1001 }, "NW", 2, 2, 5, true } }} else screen:expect{grid=[[ @@ -3305,12 +4625,10 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 2, 3, 7, true } + [4] = { { id = 1001 }, "NW", 2, 3, 7, true } }} else screen:expect{grid=[[ @@ -3353,12 +4671,10 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:some info! }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 2, 2, 0, true } + [4] = { { id = 1001 }, "NW", 2, 2, 0, true } }} else screen:expect{grid=[[ @@ -3424,10 +4740,10 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:some floaty text }| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 3, 1, true} + [4] = {{id = 1001}, "NW", 1, 3, 1, true} }} else screen:expect([[ @@ -3483,7 +4799,7 @@ describe('float window', function() meths.buf_set_lines(buf, 0, -1, true, {'such', 'very', 'float'}) local win = meths.open_win(buf, false, {relative='editor', width=15, height=4, row=2, col=10}) local expected_pos = { - [5]={{id=1002}, 'NW', 1, 2, 10, true}, + [4]={{id=1001}, 'NW', 1, 2, 10, true}, } if multigrid then screen:expect{grid=[[ @@ -3504,7 +4820,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:such }| {1:very }| {1:float }| @@ -3538,7 +4854,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:such }| {1:very }| {1:float }| @@ -3568,7 +4884,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:such }| {1:very }| {1:float }| @@ -3595,7 +4911,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:such }| {1:very }| {1:float }| @@ -3620,7 +4936,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:such }| {1:very }| {1:^float }| @@ -3628,9 +4944,9 @@ describe('float window', function() ]], float_pos=expected_pos} else screen:expect([[ - {1:very } | - {0:~ }{1:^float }{0: }| - | + {1:such } | + {0:~ }{1:very }{0: }| + ^ | ]]) end @@ -3654,7 +4970,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:such }| {1:very }| {1:^float }| @@ -3693,7 +5009,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -3730,7 +5046,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -3767,7 +5083,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -3804,7 +5120,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -3841,7 +5157,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -3878,7 +5194,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -3915,7 +5231,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -3952,7 +5268,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -3980,7 +5296,7 @@ describe('float window', function() | ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -4012,7 +5328,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^such }| {1:very }| {1:float }| @@ -4162,8 +5478,8 @@ describe('float window', function() describe('and completion', function() before_each(function() local buf = meths.create_buf(false,false) - local win = meths.open_win(buf, true, {relative='editor', width=12, height=4, row=2, col=5}) - meths.win_set_option(win , 'winhl', 'Normal:ErrorMsg') + local win = meths.open_win(buf, true, {relative='editor', width=12, height=4, row=2, col=5}).id + meths.set_option_value('winhl', 'Normal:ErrorMsg', {win=win}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -4672,12 +5988,12 @@ describe('float window', function() {13:aa }| {1:word }| {1:longtext }| - ## grid 6 + ## grid 5 {15:some info }| {15:about item }| ]], float_pos={ [4] = {{id = -1}, "NW", 2, 1, 0, false, 100}, - [6] = {{id = 1002}, "NW", 2, 1, 12, true, 50}, + [5] = {{id = 1001}, "NW", 2, 1, 12, true, 50}, }} else screen:expect([[ @@ -4713,11 +6029,11 @@ describe('float window', function() {0:~ }| ## grid 3 {3:-- INSERT --} | - ## grid 6 + ## grid 5 {15:some info }| {15:about item }| ]], float_pos={ - [6] = {{id = 1002}, "NW", 2, 1, 12, true}, + [5] = {{id = 1001}, "NW", 2, 1, 12, true}, }} else screen:expect([[ @@ -4840,6 +6156,53 @@ describe('float window', function() end) end) + it("can use Normal as background", function() + local buf = meths.create_buf(false,false) + meths.buf_set_lines(buf,0,-1,true,{"here", "float"}) + local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) + meths.set_option_value('winhl', 'Normal:Normal', {win=win}) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + here | + float | + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 2, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }here {0: }| + {0:~ }float {0: }| + {0:~ }| + {0:~ }| + | + ]]} + end + end) + describe("handles :wincmd", function() local win local expected_pos @@ -5153,7 +6516,7 @@ describe('float window', function() end if multigrid then - meths.input_mouse('left', 'press', '', 1, 0, 0) + meths.input_mouse('left', 'press', '', 2, 0, 0) screen:expect{grid=[[ ## grid 1 [2:----------------------------------------]| @@ -5232,7 +6595,7 @@ describe('float window', function() end if multigrid then - meths.input_mouse('left', 'press', '', 1, 0, 0) + meths.input_mouse('left', 'press', '', 2, 0, 0) screen:expect{grid=[[ ## grid 1 [2:----------------------------------------]| @@ -7142,18 +8505,18 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:foo }| {1:bar }| {1:baz }| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 2, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 2, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} - meths.input_mouse('left', 'press', '', 5, 0, 0) + meths.input_mouse('left', 'press', '', 4, 0, 0) screen:expect{grid=[[ ## grid 1 [2:----------------------------------------]| @@ -7172,18 +8535,18 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {1:^foo }| {1:bar }| {1:baz }| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 2, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 2, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} - meths.input_mouse('left', 'drag', '', 5, 1, 2) + meths.input_mouse('left', 'drag', '', 4, 1, 2) screen:expect{grid=[[ ## grid 1 [2:----------------------------------------]| @@ -7202,15 +8565,15 @@ describe('float window', function() {0:~ }| ## grid 3 {3:-- VISUAL --} | - ## grid 5 + ## grid 4 {27:foo}{1: }| {27:ba}{1:^r }| {1:baz }| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 2, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 2, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -7270,20 +8633,20 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:┌────────────────────┐}| {5:│}{1:foo }{5:│}| {5:│}{1:bar }{5:│}| {5:│}{1:baz }{5:│}| {5:└────────────────────┘}| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} - meths.input_mouse('left', 'press', '', 5, 1, 1) + meths.input_mouse('left', 'press', '', 4, 1, 1) screen:expect{grid=[[ ## grid 1 [2:----------------------------------------]| @@ -7302,20 +8665,20 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:┌────────────────────┐}| {5:│}{1:^foo }{5:│}| {5:│}{1:bar }{5:│}| {5:│}{1:baz }{5:│}| {5:└────────────────────┘}| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} - meths.input_mouse('left', 'drag', '', 5, 2, 3) + meths.input_mouse('left', 'drag', '', 4, 2, 3) screen:expect{grid=[[ ## grid 1 [2:----------------------------------------]| @@ -7334,17 +8697,17 @@ describe('float window', function() {0:~ }| ## grid 3 {3:-- VISUAL --} | - ## grid 5 + ## grid 4 {5:┌────────────────────┐}| {5:│}{27:foo}{1: }{5:│}| {5:│}{27:ba}{1:^r }{5:│}| {5:│}{1:baz }{5:│}| {5:└────────────────────┘}| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -7385,7 +8748,7 @@ describe('float window', function() local buf = meths.create_buf(false,false) meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'}) local float_win = meths.open_win(buf, false, {relative='editor', width=20, height=4, row=1, col=5}) - meths.win_set_option(float_win, 'winbar', 'floaty bar') + meths.set_option_value('winbar', 'floaty bar', {win=float_win.id}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -7405,19 +8768,19 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {3:floaty bar }| {1:foo }| {1:bar }| {1:baz }| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 1, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} - meths.input_mouse('left', 'press', '', 5, 1, 0) + meths.input_mouse('left', 'press', '', 4, 1, 0) screen:expect{grid=[[ ## grid 1 [2:----------------------------------------]| @@ -7436,19 +8799,19 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {3:floaty bar }| {1:^foo }| {1:bar }| {1:baz }| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 1, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} - meths.input_mouse('left', 'drag', '', 5, 2, 2) + meths.input_mouse('left', 'drag', '', 4, 2, 2) screen:expect{grid=[[ ## grid 1 [2:----------------------------------------]| @@ -7467,16 +8830,16 @@ describe('float window', function() {0:~ }| ## grid 3 {3:-- VISUAL --} | - ## grid 5 + ## grid 4 {3:floaty bar }| {27:foo}{1: }| {27:ba}{1:^r }| {1:baz }| ]], float_pos={ - [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50}; + [4] = {{id = 1001}, "NW", 1, 1, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -7521,11 +8884,11 @@ describe('float window', function() if multigrid then screen:expect([[ ## grid 1 - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| {5:[No Name] }{4:[No Name] [+] }| [3:----------------------------------------]| ## grid 2 @@ -7536,7 +8899,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 ^foo | bar | baz | @@ -7544,14 +8907,14 @@ describe('float window', function() {0:~ }| ]]) - meths.input_mouse('left', 'press', '', 5, 2, 2) + meths.input_mouse('left', 'press', '', 4, 2, 2) screen:expect([[ ## grid 1 - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| {5:[No Name] }{4:[No Name] [+] }| [3:----------------------------------------]| ## grid 2 @@ -7562,7 +8925,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 foo | bar | ba^z | @@ -7570,14 +8933,14 @@ describe('float window', function() {0:~ }| ]]) - meths.input_mouse('left', 'drag', '', 5, 1, 1) + meths.input_mouse('left', 'drag', '', 4, 1, 1) screen:expect([[ ## grid 1 - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| - [2:-------------------]{5:│}[5:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| + [2:-------------------]{5:│}[4:--------------------]| {5:[No Name] }{4:[No Name] [+] }| [3:----------------------------------------]| ## grid 2 @@ -7588,7 +8951,7 @@ describe('float window', function() {0:~ }| ## grid 3 {3:-- VISUAL --} | - ## grid 5 + ## grid 4 foo | b^a{27:r} | {27:baz} | @@ -7630,6 +8993,186 @@ describe('float window', function() end end) + it('left click sets correct curswant in float window with border', function() + local buf = meths.create_buf(false,false) + meths.buf_set_lines(buf, 0, -1, true, {'', '', ''}) + meths.open_win(buf, false, {relative='editor', width=20, height=3, row=0, col=5, border='single'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {5:┌────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ {5:┌────────────────────┐} | + {0:~ }{5:│}{1: }{5:│}{0: }| + {0:~ }{5:│}{1: }{5:│}{0: }| + {0:~ }{5:│}{1: }{5:│}{0: }| + {0:~ }{5:└────────────────────┘}{0: }| + {0:~ }| + | + ]]} + end + + if multigrid then + meths.input_mouse('left', 'press', '', 4, 3, 1) + else + meths.input_mouse('left', 'press', '', 0, 3, 6) + end + eq({0, 3, 1, 0, 1}, funcs.getcurpos()) + + if multigrid then + meths.input_mouse('left', 'press', '', 4, 3, 2) + else + meths.input_mouse('left', 'press', '', 0, 3, 7) + end + eq({0, 3, 1, 0, 2}, funcs.getcurpos()) + + if multigrid then + meths.input_mouse('left', 'press', '', 4, 3, 10) + else + meths.input_mouse('left', 'press', '', 0, 3, 15) + end + eq({0, 3, 1, 0, 10}, funcs.getcurpos()) + + command('setlocal foldcolumn=1') + feed('zfkgg') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {5:┌────────────────────┐}| + {5:│}{19: }{1:^ }{5:│}| + {5:│}{19:+}{28:+-- 2 lines: ·····}{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────────────────────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 4, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {5:┌────────────────────┐} | + {0:~ }{5:│}{19: }{1:^ }{5:│}{0: }| + {0:~ }{5:│}{19:+}{28:+-- 2 lines: ·····}{5:│}{0: }| + {0:~ }{5:│}{2:~ }{5:│}{0: }| + {0:~ }{5:└────────────────────┘}{0: }| + {0:~ }| + | + ]]} + end + + if multigrid then + meths.input_mouse('left', 'press', '', 4, 2, 1) + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {5:┌────────────────────┐}| + {5:│}{19: }{1:^ }{5:│}| + {5:│}{19:-}{1: }{5:│}| + {5:│}{19:│}{1: }{5:│}| + {5:└────────────────────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; + }} + else + meths.input_mouse('left', 'press', '', 0, 2, 6) + screen:expect{grid=[[ + {5:┌────────────────────┐} | + {0:~ }{5:│}{19: }{1:^ }{5:│}{0: }| + {0:~ }{5:│}{19:-}{1: }{5:│}{0: }| + {0:~ }{5:│}{19:│}{1: }{5:│}{0: }| + {0:~ }{5:└────────────────────┘}{0: }| + {0:~ }| + | + ]]} + end + + if multigrid then + meths.input_mouse('left', 'press', '', 4, 2, 2) + else + meths.input_mouse('left', 'press', '', 0, 2, 7) + end + eq({0, 2, 1, 0, 1}, funcs.getcurpos()) + + if multigrid then + meths.input_mouse('left', 'press', '', 4, 2, 3) + else + meths.input_mouse('left', 'press', '', 0, 2, 8) + end + eq({0, 2, 1, 0, 2}, funcs.getcurpos()) + + if multigrid then + meths.input_mouse('left', 'press', '', 4, 2, 11) + else + meths.input_mouse('left', 'press', '', 0, 2, 16) + end + eq({0, 2, 1, 0, 10}, funcs.getcurpos()) + end) + it("'winblend' option", function() screen:try_resize(50,9) screen:set_default_attr_ids({ @@ -7641,10 +9184,23 @@ describe('float window', function() [6] = {foreground = tonumber('0x332533'), background = tonumber('0xfff1ff')}, [7] = {background = tonumber('0xffcfff'), bold = true, foreground = tonumber('0x0000d8')}, [8] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1}, - [9] = {background = Screen.colors.LightMagenta, blend=30}, - [10] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend=0}, - [11] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend=80}, - [12] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1, blend=30}, + [9] = {background = Screen.colors.LightMagenta, blend = 30}, + [10] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend = 0}, + [11] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend = 80}, + [12] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1, blend = 30}, + [13] = {background = Screen.colors.LightGray, blend = 30}, + [14] = {foreground = Screen.colors.Grey0, background = Screen.colors.Grey88}, + [15] = {foreground = tonumber('0x939393'), background = Screen.colors.Grey88}, + [16] = {background = Screen.colors.Grey90}; + [17] = {blend = 100}; + [18] = {background = Screen.colors.LightMagenta, blend = 100}; + [19] = {background = Screen.colors.LightMagenta, bold = true, blend = 100, foreground = Screen.colors.Blue1}; + [20] = {background = Screen.colors.White, foreground = Screen.colors.Gray0}; + [21] = {background = Screen.colors.White, bold = true, foreground = tonumber('0x00007f')}; + [22] = {background = Screen.colors.Gray90, foreground = Screen.colors.Gray0}; + [23] = {blend = 100, bold = true, foreground = Screen.colors.Magenta}; + [24] = {foreground = tonumber('0x7f007f'), bold = true, background = Screen.colors.White}; + [25] = {foreground = tonumber('0x7f007f'), bold = true, background = Screen.colors.Grey90}; }) insert([[ Lorem ipsum dolor sit amet, consectetur @@ -7684,11 +9240,11 @@ describe('float window', function() laborum^. | ## grid 3 | - ## grid 5 + ## grid 4 {1:test }| {1: }| {1:popup text }| - ]], float_pos={[5] = {{id = 1002}, "NW", 1, 2, 5, true}}} + ]], float_pos={[4] = {{id = 1001}, "NW", 1, 2, 5, true}}} else screen:expect([[ Ut enim ad minim veniam, quis nostrud | @@ -7703,7 +9259,7 @@ describe('float window', function() ]]) end - meths.win_set_option(win, "winblend", 30) + meths.set_option_value("winblend", 30, {win=win.id}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -7727,11 +9283,11 @@ describe('float window', function() laborum^. | ## grid 3 | - ## grid 5 + ## grid 4 {9:test }| {9: }| {9:popup text }| - ]], float_pos={[5] = {{id = 1002}, "NW", 1, 2, 5, true}}, unchanged=true} + ]], float_pos={[4] = {{id = 1001}, "NW", 1, 2, 5, true}}, unchanged=true} else screen:expect([[ Ut enim ad minim veniam, quis nostrud | @@ -7746,6 +9302,58 @@ describe('float window', function() ]]) end + -- Check that 'winblend' works with NormalNC highlight + meths.set_option_value('winhighlight', 'NormalNC:Visual', {win = win}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [3:--------------------------------------------------]| + ## grid 2 + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum^. | + ## grid 3 + | + ## grid 4 + {13:test }| + {13: }| + {13:popup text }| + ]], float_pos={[4] = {{id = 1001}, "NW", 1, 2, 5, true}}} + else + screen:expect([[ + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + ea co{14:test}{15:o consequat}. Duis aute irure dolor in | + repre{15:henderit in vol}uptate velit esse cillum | + dolor{14:popup}{15:fugi}{14:text}{15:ul}la pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum^. | + | + ]]) + end + + -- Also test with global NormalNC highlight + exec_lua([[ + vim.api.nvim_set_option_value('winhighlight', '', {win = ...}) + vim.api.nvim_set_hl(0, 'NormalNC', {link = 'Visual'}) + ]], win) + screen:expect_unchanged() + command('hi clear NormalNC') + command('hi SpecialRegion guifg=Red blend=0') meths.buf_add_highlight(buf, -1, "SpecialRegion", 2, 0, -1) if multigrid then @@ -7771,11 +9379,11 @@ describe('float window', function() laborum^. | ## grid 3 | - ## grid 5 + ## grid 4 {9:test }| {9: }| {10:popup text}{9: }| - ]], float_pos={[5] = {{id = 1002}, "NW", 1, 2, 5, true}}} + ]], float_pos={[4] = {{id = 1001}, "NW", 1, 2, 5, true}}} else screen:expect([[ Ut enim ad minim veniam, quis nostrud | @@ -7814,11 +9422,11 @@ describe('float window', function() laborum^. | ## grid 3 | - ## grid 5 + ## grid 4 {9:test }| {9: }| {11:popup text}{9: }| - ]], float_pos={[5] = {{id = 1002}, "NW", 1, 2, 5, true}}, unchanged=true} + ]], float_pos={[4] = {{id = 1001}, "NW", 1, 2, 5, true}}, unchanged=true} else screen:expect([[ Ut enim ad minim veniam, quis nostrud | @@ -7835,7 +9443,7 @@ describe('float window', function() -- Test scrolling by mouse if multigrid then - meths.input_mouse('wheel', 'down', '', 5, 2, 2) + meths.input_mouse('wheel', 'down', '', 4, 2, 2) screen:expect{grid=[[ ## grid 1 [2:--------------------------------------------------]| @@ -7858,11 +9466,11 @@ describe('float window', function() laborum^. | ## grid 3 | - ## grid 5 + ## grid 4 {11:popup text}{9: }| {12:~ }| {12:~ }| - ]], float_pos={[5] = {{id = 1002}, "NW", 1, 2, 5, true}}} + ]], float_pos={[4] = {{id = 1001}, "NW", 1, 2, 5, true}}} else meths.input_mouse('wheel', 'down', '', 0, 4, 7) screen:expect([[ @@ -7877,6 +9485,56 @@ describe('float window', function() | ]]) end + + -- Check that 'winblend' applies to border/title/footer + meths.win_set_config(win, {border='single', title='Title', footer='Footer'}) + meths.set_option_value('winblend', 100, {win=win.id}) + meths.set_option_value("cursorline", true, {win=0}) + command('hi clear VertSplit') + feed('k0') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [3:--------------------------------------------------]| + ## grid 2 + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + {16:^qui officia deserunt mollit anim id est }| + laborum. | + ## grid 3 + | + ## grid 4 + {17:┌}{23:Title}{17:──────────┐}| + {17:│}{11:popup text}{18: }{17:│}| + {17:│}{19:~ }{17:│}| + {17:│}{19:~ }{17:│}| + {17:└}{23:Footer}{17:─────────┘}| + ]], float_pos={[4] = {{id = 1001}, "NW", 1, 2, 5, true}}} + else + screen:expect([[ + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + ea co{20:┌}{24:Title}{20:──────────┐}Duis aute irure dolor in | + repre{20:│}{5:popup}{6:it i}{5:text}{20:lu│}tate velit esse cillum | + dolor{20:│}{21:~}{20:eu fugiat null│} pariatur. Excepteur sint | + occae{20:│}{21:~}{20:t cupidatat no│} proident, sunt in culpa | + {16:^qui o}{22:└}{25:Footer}{22:─────────┘}{16:ollit anim id est }| + laborum. | + | + ]]) + end end) it('can overlap doublewidth chars', function() @@ -7884,6 +9542,7 @@ describe('float window', function() # TODO: 测试字典信息的准确性 # FIXME: 测试字典信息的准确性]]) local buf = meths.create_buf(false,false) + meths.buf_set_lines(buf, 0, -1, true, {'口', '口'}) local win = meths.open_win(buf, false, {relative='editor', width=5, height=3, row=0, col=11, style='minimal'}) if multigrid then screen:expect{grid=[[ @@ -7905,14 +9564,14 @@ describe('float window', function() ## grid 3 | ## grid 4 - {1: }| - {1: }| + {1:口 }| + {1:口 }| {1: }| ]], float_pos={ [4] = { { id = 1001 }, "NW", 1, 0, 11, true } }} else screen:expect([[ - # TODO: 测 {1: }信息的准确性 | - # FIXME: 测{1: } 信息的准确^性 | + # TODO: 测 {1:口 }信息的准确性 | + # FIXME: 测{1:口 } 信息的准确^性 | {0:~ }{1: }{0: }| {0:~ }| {0:~ }| @@ -7959,7 +9618,7 @@ describe('float window', function() -- at least. Also check invisible EndOfBuffer region blends correctly. meths.buf_set_lines(buf, 0, -1, true, {" x x x xx", " x x x x"}) win = meths.open_win(buf, false, {relative='editor', width=12, height=3, row=0, col=11, style='minimal'}) - meths.win_set_option(win, 'winblend', 30) + meths.set_option_value('winblend', 30, {win=win.id}) screen:set_default_attr_ids({ [1] = {foreground = tonumber('0xb282b2'), background = tonumber('0xffcfff')}, [2] = {foreground = Screen.colors.Grey0, background = tonumber('0xffcfff')}, @@ -7986,14 +9645,12 @@ describe('float window', function() {3:~ }| ## grid 3 | - ## grid 6 + ## grid 5 {5: x x x xx}| {5: x x x x}| {5: }| ]], float_pos={ - [6] = { { - id = 1003 - }, "NW", 1, 0, 11, true } + [5] = { { id = 1002 }, "NW", 1, 0, 11, true } }} else screen:expect([[ @@ -8027,14 +9684,12 @@ describe('float window', function() {3:~ }| ## grid 3 | - ## grid 6 + ## grid 5 {5: x x x xx}| {5: x x x x}| {5: }| ]], float_pos={ - [6] = { { - id = 1003 - }, "NW", 1, 0, 12, true } + [5] = { { id = 1002 }, "NW", 1, 0, 12, true } }} else screen:expect([[ @@ -8096,11 +9751,11 @@ describe('float window', function() {1:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {2:^long }| {2:longer }| {2:longest}| - ## grid 6 + ## grid 5 {2:---------}| {2:- -}| {2:- -}| @@ -8110,11 +9765,11 @@ describe('float window', function() [1] = {foreground = Screen.colors.Blue1, bold = true}; [2] = {background = Screen.colors.LightMagenta}; }, float_pos={ + [4] = { { + id = 1001 + }, "NW", 1, 1, 1, true }, [5] = { { id = 1002 - }, "NW", 1, 1, 1, true }, - [6] = { { - id = 1003 }, "NW", 1, 0, 0, true } }} else @@ -8164,11 +9819,11 @@ describe('float window', function() {1:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {2:^l}| {2:o}| {2:n}| - ## grid 6 + ## grid 5 {2:---}| {2:- -}| {2:- -}| @@ -8178,12 +9833,8 @@ describe('float window', function() [1] = {foreground = Screen.colors.Blue1, bold = true}; [2] = {background = Screen.colors.LightMagenta}; }, float_pos={ - [5] = { { - id = 1002 - }, "NW", 1, 1, 1, true }, - [6] = { { - id = 1003 - }, "NW", 1, 0, 0, true } + [4] = { { id = 1001 }, "NW", 1, 1, 1, true }, + [5] = { { id = 1002 }, "NW", 1, 0, 0, true } }} else screen:expect([[ @@ -8201,7 +9852,7 @@ describe('float window', function() it("correctly orders multiple opened floats (current last)", function() local buf = meths.create_buf(false,false) local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) - meths.win_set_option(win, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg") + meths.set_option_value("winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg", {win=win.id}) if multigrid then screen:expect{grid=[[ @@ -8228,8 +9879,8 @@ describe('float window', function() ]], float_pos={ [4] = { { id = 1001 }, "NW", 1, 2, 5, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8246,10 +9897,10 @@ describe('float window', function() exec_lua [[ local buf = vim.api.nvim_create_buf(false,false) local win = vim.api.nvim_open_win(buf, false, {relative='editor', width=16, height=2, row=3, col=8}) - vim.api.nvim_win_set_option(win, "winhl", "EndOfBuffer:Normal") + vim.wo[win].winhl = "EndOfBuffer:Normal" buf = vim.api.nvim_create_buf(false,false) win = vim.api.nvim_open_win(buf, true, {relative='editor', width=12, height=2, row=4, col=10}) - vim.api.nvim_win_set_option(win, "winhl", "Normal:Search,EndOfBuffer:Search") + vim.wo[win].winhl = "Normal:Search,EndOfBuffer:Search" ]] if multigrid then @@ -8285,10 +9936,10 @@ describe('float window', function() [5] = { { id = 1002 }, "NW", 1, 3, 8, true }; [6] = { { id = 1003 }, "NW", 1, 4, 10, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; - [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8306,7 +9957,7 @@ describe('float window', function() it("correctly orders multiple opened floats (non-current last)", function() local buf = meths.create_buf(false,false) local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) - meths.win_set_option(win, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg") + meths.set_option_value("winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg", {win=win.id}) if multigrid then screen:expect{grid=[[ @@ -8333,8 +9984,8 @@ describe('float window', function() ]], float_pos={ [4] = { { id = 1001 }, "NW", 1, 2, 5, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8351,10 +10002,10 @@ describe('float window', function() exec_lua [[ local buf = vim.api.nvim_create_buf(false,false) local win = vim.api.nvim_open_win(buf, true, {relative='editor', width=12, height=2, row=4, col=10}) - vim.api.nvim_win_set_option(win, "winhl", "Normal:Search,EndOfBuffer:Search") + vim.wo[win].winhl = "Normal:Search,EndOfBuffer:Search" buf = vim.api.nvim_create_buf(false,false) win = vim.api.nvim_open_win(buf, false, {relative='editor', width=16, height=2, row=3, col=8}) - vim.api.nvim_win_set_option(win, "winhl", "EndOfBuffer:Normal") + vim.wo[win].winhl = "EndOfBuffer:Normal" ]] if multigrid then @@ -8390,10 +10041,10 @@ describe('float window', function() [5] = { { id = 1002 }, "NW", 1, 4, 10, true }; [6] = { { id = 1003 }, "NW", 1, 3, 8, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8411,11 +10062,11 @@ describe('float window', function() it('can use z-index', function() local buf = meths.create_buf(false,false) local win1 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=1, col=5, zindex=30}) - meths.win_set_option(win1, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg") + meths.set_option_value("winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg", {win=win1.id}) local win2 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=2, col=6, zindex=50}) - meths.win_set_option(win2, "winhl", "Normal:Search,EndOfBuffer:Search") + meths.set_option_value("winhl", "Normal:Search,EndOfBuffer:Search", {win=win2.id}) local win3 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=3, col=7, zindex=40}) - meths.win_set_option(win3, "winhl", "Normal:Question,EndOfBuffer:Question") + meths.set_option_value("winhl", "Normal:Question,EndOfBuffer:Question", {win=win3.id}) if multigrid then screen:expect{grid=[[ @@ -8453,10 +10104,10 @@ describe('float window', function() [5] = {{id = 1002}, "NW", 1, 2, 6, true, 50}; [6] = {{id = 1003}, "NW", 1, 3, 7, true, 40}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8474,7 +10125,7 @@ describe('float window', function() it('can use winbar', function() local buf = meths.create_buf(false,false) local win1 = meths.open_win(buf, false, {relative='editor', width=15, height=3, row=1, col=5}) - meths.win_set_option(win1, 'winbar', 'floaty bar') + meths.set_option_value('winbar', 'floaty bar', {win=win1.id}) if multigrid then screen:expect{grid=[[ @@ -8502,8 +10153,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8549,8 +10200,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 0, 4, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8594,7 +10245,7 @@ describe('float window', function() {0:~ }| {0:~ }| ## grid 3 - ## grid 5 + ## grid 4 {5:┌────────────────────────────────────────┐}| {5:│}{1: }{5:│}| {5:│}{1: }{5:│}| @@ -8602,10 +10253,10 @@ describe('float window', function() {5:│}{1: }{5:│}| {5:└────────────────────────────────────────┘}| ]], float_pos={ - [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50}; + [4] = {{id = 1001}, "SW", 1, 9, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8650,16 +10301,16 @@ describe('float window', function() {0:~ }| {0:~ }| ## grid 3 - ## grid 5 + ## grid 4 {5:┌────────────────────────────────────────┐}| {5:│}{1: }{5:│}| {5:│}{1: }{5:│}| {5:└────────────────────────────────────────┘}| ]], float_pos={ - [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50}; + [4] = {{id = 1001}, "SW", 1, 9, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8701,7 +10352,7 @@ describe('float window', function() {0:~ }| ## grid 3 ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8746,7 +10397,7 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:┌────────────────────────────────────────┐}| {5:│}{1: }{5:│}| {5:│}{1: }{5:│}| @@ -8754,10 +10405,10 @@ describe('float window', function() {5:│}{1: }{5:│}| {5:└────────────────────────────────────────┘}| ]], float_pos={ - [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + [4] = {{id = 1001}, "SW", 1, 8, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8806,7 +10457,7 @@ describe('float window', function() ## grid 3 | {8:Press ENTER or type command to continue}^ | - ## grid 5 + ## grid 4 {5:┌────────────────────────────────────────┐}| {5:│}{1: }{5:│}| {5:│}{1: }{5:│}| @@ -8814,10 +10465,10 @@ describe('float window', function() {5:│}{1: }{5:│}| {5:└────────────────────────────────────────┘}| ]], float_pos={ - [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + [4] = {{id = 1001}, "SW", 1, 8, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8857,16 +10508,16 @@ describe('float window', function() {0:~ }| ## grid 3 | - ## grid 5 + ## grid 4 {5:┌────────────────────────────────────────┐}| {5:│}{1: }{5:│}| {5:│}{1: }{5:│}| {5:└────────────────────────────────────────┘}| ]], float_pos={ - [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + [4] = {{id = 1001}, "SW", 1, 8, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8907,9 +10558,8 @@ describe('float window', function() ## grid 3 | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} - else screen:expect{grid=[[ ^ | @@ -8952,6 +10602,696 @@ describe('float window', function() test_float_move_close('autocmd BufWinLeave * ++once redraw') end) end) + + it(':sleep cursor placement #22639', function() + local float_opts = {relative = 'editor', row = 1, col = 1, width = 4, height = 3} + local win = meths.open_win(meths.create_buf(false, false), true, float_opts) + feed('iab<CR>cd<Esc>') + feed(':sleep 100') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100^ | + ## grid 4 + {1:ab }| + {1:cd }| + {2:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~}{1:ab }{0: }| + {0:~}{1:cd }{0: }| + {0:~}{2:~ }{0: }| + {0:~ }| + {0:~ }| + :sleep 100^ | + ]]} + end + + feed('<CR>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100 | + ## grid 4 + {1:ab }| + {1:c^d }| + {2:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~}{1:ab }{0: }| + {0:~}{1:c^d }{0: }| + {0:~}{2:~ }{0: }| + {0:~ }| + {0:~ }| + :sleep 100 | + ]]} + end + feed('<C-C>') + screen:expect_unchanged() + + meths.win_set_config(win, {border = 'single'}) + feed(':sleep 100') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100^ | + ## grid 4 + {5:┌────┐}| + {5:│}{1:ab }{5:│}| + {5:│}{1:cd }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌────┐}{0: }| + {0:~}{5:│}{1:ab }{5:│}{0: }| + {0:~}{5:│}{1:cd }{5:│}{0: }| + {0:~}{5:│}{2:~ }{5:│}{0: }| + {0:~}{5:└────┘}{0: }| + :sleep 100^ | + ]]} + end + + feed('<CR>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100 | + ## grid 4 + {5:┌────┐}| + {5:│}{1:ab }{5:│}| + {5:│}{1:c^d }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌────┐}{0: }| + {0:~}{5:│}{1:ab }{5:│}{0: }| + {0:~}{5:│}{1:c^d }{5:│}{0: }| + {0:~}{5:│}{2:~ }{5:│}{0: }| + {0:~}{5:└────┘}{0: }| + :sleep 100 | + ]]} + end + feed('<C-C>') + screen:expect_unchanged() + + command('setlocal winbar=foo') + feed(':sleep 100') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100^ | + ## grid 4 + {5:┌────┐}| + {5:│}{3:foo }{5:│}| + {5:│}{1:ab }{5:│}| + {5:│}{1:cd }{5:│}| + {5:└────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌────┐}{0: }| + {0:~}{5:│}{3:foo }{5:│}{0: }| + {0:~}{5:│}{1:ab }{5:│}{0: }| + {0:~}{5:│}{1:cd }{5:│}{0: }| + {0:~}{5:└────┘}{0: }| + :sleep 100^ | + ]]} + end + + feed('<CR>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100 | + ## grid 4 + {5:┌────┐}| + {5:│}{3:foo }{5:│}| + {5:│}{1:ab }{5:│}| + {5:│}{1:c^d }{5:│}| + {5:└────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌────┐}{0: }| + {0:~}{5:│}{3:foo }{5:│}{0: }| + {0:~}{5:│}{1:ab }{5:│}{0: }| + {0:~}{5:│}{1:c^d }{5:│}{0: }| + {0:~}{5:└────┘}{0: }| + :sleep 100 | + ]]} + end + feed('<C-C>') + screen:expect_unchanged() + end) + + it('with rightleft and border #22640', function() + local float_opts = {relative='editor', width=5, height=3, row=1, col=1, border='single'} + meths.open_win(meths.create_buf(false, false), true, float_opts) + command('setlocal rightleft') + feed('iabc<CR>def<Esc>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {5:┌─────┐}| + {5:│}{1: cba}{5:│}| + {5:│}{1: ^fed}{5:│}| + {5:│}{2: ~}{5:│}| + {5:└─────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌─────┐}{0: }| + {0:~}{5:│}{1: cba}{5:│}{0: }| + {0:~}{5:│}{1: ^fed}{5:│}{0: }| + {0:~}{5:│}{2: ~}{5:│}{0: }| + {0:~}{5:└─────┘}{0: }| + | + ]]} + end + end) + + it('float window with hide option', function() + local buf = meths.create_buf(false,false) + local win = meths.open_win(buf, false, {relative='editor', width=10, height=2, row=2, col=5, hide = true}) + local expected_pos = { + [4]={{id=1001}, 'NW', 1, 2, 5, true}, + } + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ## grid 4 (hidden) + {1: }| + {2:~ }| + ]], float_pos = {}} + else + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + meths.win_set_config(win, {hide = false}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ## grid 4 + {1: }| + {2:~ }| + ]], float_pos = expected_pos} + else + screen:expect([[ + ^ | + {0:~ }| + {0:~ }{1: }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]) + end + + meths.win_set_config(win, {hide=true}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ## grid 4 (hidden) + {1: }| + {2:~ }| + ]], float_pos = {}} + else + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + end) + + it(':fclose command #9663', function() + local buf_a = meths.create_buf(false,false) + local buf_b = meths.create_buf(false,false) + local buf_c = meths.create_buf(false,false) + local buf_d = meths.create_buf(false,false) + local config_a = {relative='editor', width=11, height=11, row=5, col=5, border ='single', zindex=50} + local config_b = {relative='editor', width=8, height=8, row=7, col=7, border ='single', zindex=70} + local config_c = {relative='editor', width=4, height=4, row=9, col=9, border ='single',zindex=90} + local config_d = {relative='editor', width=2, height=2, row=10, col=10, border ='single',zindex=100} + meths.open_win(buf_a, false, config_a) + meths.open_win(buf_b, false, config_b) + meths.open_win(buf_c, false, config_c) + meths.open_win(buf_d, false, config_d) + local expected_pos = { + [4]={{id=1001}, 'NW', 1, 5, 5, true, 50}, + [5]={{id=1002}, 'NW', 1, 7, 7, true, 70}, + [6]={{id=1003}, 'NW', 1, 9, 9, true, 90}, + [7]={{id=1004}, 'NW', 1, 10, 10, true, 100}, + } + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {5:┌───────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└───────────┘}| + ## grid 5 + {5:┌────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────────┘}| + ## grid 6 + {5:┌────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────┘}| + ## grid 7 + {5:┌──┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└──┘}| + ]], float_pos=expected_pos} + else + screen:expect([[ + ^ {5:┌─┌─┌────┐─┐┐} | + {0:~ }{5:│}{1: }{5:│}{1: }{5:│}{1: }{5:│}{1: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:│┌──┐│}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:││}{1: }{5:││}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:││}{2:~ }{5:││}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:└└──┘┘}{2: }{5:││}{0: }| + | + ]]) + end + -- close the window with the highest zindex value + command('fclose') + expected_pos[7] = nil + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ## grid 4 + {5:┌───────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└───────────┘}| + ## grid 5 + {5:┌────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────────┘}| + ## grid 6 + {5:┌────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────┘}| + ]], float_pos=expected_pos} + else + screen:expect([[ + ^ {5:┌─┌─┌────┐─┐┐} | + {0:~ }{5:│}{1: }{5:│}{1: }{5:│}{1: }{5:│}{1: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:│}{2:~ }{5:│}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:│}{2:~ }{5:│}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:│}{2:~ }{5:│}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:└────┘}{2: }{5:││}{0: }| + | + ]]) + end + -- with range + command('1fclose') + expected_pos[6] = nil + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ## grid 4 + {5:┌───────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└───────────┘}| + ## grid 5 + {5:┌────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────────┘}| + ]], float_pos=expected_pos} + else + screen:expect([[ + ^ {5:┌─┌────────┐┐} | + {0:~ }{5:│}{1: }{5:│}{1: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~ }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~ }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~ }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~ }{5:││}{0: }| + | + ]]) + end + -- with bang + command('fclose!') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ]], float_pos={}} + else + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + 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 46a478c1ea..1addf7088e 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -4,11 +4,9 @@ local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local command = helpers.command local feed_command = helpers.feed_command local insert = helpers.insert -local expect = helpers.expect local funcs = helpers.funcs local meths = helpers.meths local exec = helpers.exec -local exec_lua = helpers.exec_lua local assert_alive = helpers.assert_alive @@ -29,23 +27,29 @@ describe("folded lines", function() local function with_ext_multigrid(multigrid) local screen before_each(function() - clear() - command('hi VertSplit gui=reverse') screen = Screen.new(45, 8) screen:attach({rgb=true, ext_multigrid=multigrid}) screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {reverse = true}, [3] = {bold = true, reverse = true}, - [4] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {foreground = Screen.colors.White, background = Screen.colors.Red}, [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey}, [6] = {background = Screen.colors.Yellow}, [7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray}, [8] = {foreground = Screen.colors.Brown }, [9] = {bold = true, foreground = Screen.colors.Brown}, [10] = {background = Screen.colors.LightGrey, underline = true}, - [11] = {bold=true}, - [12] = {background = Screen.colors.Grey90}, + [11] = {bold = true}, + [12] = {foreground = Screen.colors.Red}, + [13] = {foreground = Screen.colors.Red, background = Screen.colors.LightGrey}, + [14] = {background = Screen.colors.Red}, + [15] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Red}, + [16] = {background = Screen.colors.LightGrey}, + [17] = {background = Screen.colors.Yellow, foreground = Screen.colors.Red}, + [18] = {background = Screen.colors.LightGrey, bold = true, foreground = Screen.colors.Blue}, + [19] = {background = Screen.colors.Yellow, foreground = Screen.colors.DarkBlue}, + [20] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue}, }) end) @@ -89,11 +93,11 @@ describe("folded lines", function() end end) - it("highlights with CursorLineFold when 'cursorline' is set", function() - command("set cursorline foldcolumn=2 foldmethod=marker") + local function test_folded_cursorline() + command("set number cursorline foldcolumn=2") command("hi link CursorLineFold Search") insert(content1) - feed("zf3j") + feed("ggzf3jj") if multigrid then screen:expect([[ ## grid 1 @@ -106,26 +110,26 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }in his cave. | - {6: }{12:^ }| + {7:+ }{8: 1 }{5:+-- 4 lines: This is a················}| + {6: }{9: 5 }{12:^in his cave. }| + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }in his cave. | - {6: }{12:^ }| - {1:~ }| - | + {7:+ }{8: 1 }{5:+-- 4 lines: This is a················}| + {6: }{9: 5 }{12:^in his cave. }| + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end feed("k") @@ -141,28 +145,34 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {6: }{12:^in his cave. }| - {7: } | + {6:+ }{9: 1 }{13:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {6: }{12:^in his cave. }| - {7: } | - {1:~ }| - | + {6:+ }{9: 1 }{13:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end + -- CursorLine is applied correctly with screenrow motions #22232 + feed("jgk") + screen:expect_unchanged() + -- CursorLine is applied correctly when closing a fold when cursor is not at fold start + feed("zo4Gzc") + screen:expect_unchanged() command("set cursorlineopt=line") if multigrid then screen:expect([[ @@ -176,28 +186,79 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }{12:^in his cave. }| - {7: } | + {7:+ }{8: 1 }{13:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }{12:^in his cave. }| - {7: } | - {1:~ }| - | + {7:+ }{8: 1 }{13:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + command("set relativenumber cursorlineopt=number") + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {6:+ }{9:1 }{5:^+-- 4 lines: This is a················}| + {7: }{8: 1 }in his cave. | + {7: }{8: 2 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {6:+ }{9:1 }{5:^+-- 4 lines: This is a················}| + {7: }{8: 1 }in his cave. | + {7: }{8: 2 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end + end + + describe("when 'cursorline' is set", function() + it('with high-priority CursorLine', function() + command("hi! CursorLine guibg=NONE guifg=Red gui=NONE") + test_folded_cursorline() + end) + + it('with low-priority CursorLine', function() + command("hi! CursorLine guibg=NONE guifg=NONE gui=underline") + local attrs = screen:get_default_attr_ids() + attrs[12] = {underline = true} + attrs[13] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey, underline = true} + screen:set_default_attr_ids(attrs) + test_folded_cursorline() + end) end) it("work with spell", function() @@ -362,6 +423,119 @@ describe("folded lines", function() :set norightleft | ]]) end + + if multigrid then + meths.input_mouse('left', 'press', '', 2, 0, 0) + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {7:▸ }{5:^+-- 6 lines: aa···························}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :set norightleft | + ]]) + else + meths.input_mouse('left', 'press', '', 0, 0, 0) + screen:expect([[ + {7:▸ }{5:^+-- 6 lines: aa···························}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :set norightleft | + ]]) + end + + -- Add a winbar to avoid double-clicks + command('setlocal winbar=!!!!!!') + if multigrid then + meths.input_mouse('left', 'press', '', 2, 1, 0) + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {11:!!!!!! }| + {7:▾▸}{5:^+--- 5 lines: aa··························}| + {7:│ }ff | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :set norightleft | + ]]) + else + meths.input_mouse('left', 'press', '', 0, 1, 0) + screen:expect([[ + {11:!!!!!! }| + {7:▾▸}{5:^+--- 5 lines: aa··························}| + {7:│ }ff | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :set norightleft | + ]]) + end + + if multigrid then + meths.input_mouse('left', 'press', '', 2, 1, 1) + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {11:!!!!!! }| + {7:▾▾}^aa | + {7:││}bb | + {7:││}cc | + {7:││}dd | + {7:││}ee | + {7:│ }ff | + ## grid 3 + :set norightleft | + ]]) + else + meths.input_mouse('left', 'press', '', 0, 1, 1) + screen:expect([[ + {11:!!!!!! }| + {7:▾▾}^aa | + {7:││}bb | + {7:││}cc | + {7:││}dd | + {7:││}ee | + {7:│ }ff | + :set norightleft | + ]]) + end end) it("works with split", function() @@ -928,9 +1102,7 @@ describe("folded lines", function() end) it("works with multibyte text", function() - -- Currently the only allowed value of 'maxcombine' - eq(6, meths.get_option('maxcombine')) - eq(true, meths.get_option('arabicshape')) + eq(true, meths.get_option_value('arabicshape', {})) insert([[ å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢͟ العَرَبِيَّة möre text]]) @@ -946,7 +1118,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - å 语 x̎͂̀̂͛͛ ﺎﻠﻋَﺮَﺒِﻳَّﺓ | + å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ ﺎﻠﻋَﺮَﺒِﻳَّﺓ | möre tex^t | {1:~ }| {1:~ }| @@ -958,7 +1130,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - å 语 x̎͂̀̂͛͛ ﺎﻠﻋَﺮَﺒِﻳَّﺓ | + å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ ﺎﻠﻋَﺮَﺒِﻳَّﺓ | möre tex^t | {1:~ }| {1:~ }| @@ -982,7 +1154,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {5:^+-- 2 lines: å 语 x̎͂̀̂͛͛ العَرَبِيَّة·················}| + {5:^+-- 2 lines: å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ ﺎﻠﻋَﺮَﺒِﻳَّﺓ·················}| {1:~ }| {1:~ }| {1:~ }| @@ -994,7 +1166,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - {5:^+-- 2 lines: å 语 x̎͂̀̂͛͛ العَرَبِيَّة·················}| + {5:^+-- 2 lines: å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ ﺎﻠﻋَﺮَﺒِﻳَّﺓ·················}| {1:~ }| {1:~ }| {1:~ }| @@ -1018,7 +1190,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {5:^+-- 2 lines: å 语 x̎͂̀̂͛͛ العَرَبِيَّة·················}| + {5:^+-- 2 lines: å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ العَرَبِيَّة·················}| {1:~ }| {1:~ }| {1:~ }| @@ -1030,7 +1202,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - {5:^+-- 2 lines: å 语 x̎͂̀̂͛͛ العَرَبِيَّة·················}| + {5:^+-- 2 lines: å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ العَرَبِيَّة·················}| {1:~ }| {1:~ }| {1:~ }| @@ -1054,7 +1226,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7:+ }{8: 1 }{5:^+-- 2 lines: å 语 x̎͂̀̂͛͛ العَرَبِيَّة···········}| + {7:+ }{8: 1 }{5:^+-- 2 lines: å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ العَرَبِيَّة···········}| {1:~ }| {1:~ }| {1:~ }| @@ -1066,7 +1238,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - {7:+ }{8: 1 }{5:^+-- 2 lines: å 语 x̎͂̀̂͛͛ العَرَبِيَّة···········}| + {7:+ }{8: 1 }{5:^+-- 2 lines: å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ العَرَبِيَّة···········}| {1:~ }| {1:~ }| {1:~ }| @@ -1091,7 +1263,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {5:···········ةيَّبِرَعَلا x̎͂̀̂͛͛ 语 å :senil 2 --^+}{8: 1 }{7: +}| + {5:···········ةيَّبِرَعَلا x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å :senil 2 --^+}{8: 1 }{7: +}| {1: ~}| {1: ~}| {1: ~}| @@ -1103,7 +1275,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - {5:···········ةيَّبِرَعَلا x̎͂̀̂͛͛ 语 å :senil 2 --^+}{8: 1 }{7: +}| + {5:···········ةيَّبِرَعَلا x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å :senil 2 --^+}{8: 1 }{7: +}| {1: ~}| {1: ~}| {1: ~}| @@ -1127,7 +1299,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {5:·················ةيَّبِرَعَلا x̎͂̀̂͛͛ 语 å :senil 2 --^+}| + {5:·················ةيَّبِرَعَلا x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å :senil 2 --^+}| {1: ~}| {1: ~}| {1: ~}| @@ -1139,7 +1311,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - {5:·················ةيَّبِرَعَلا x̎͂̀̂͛͛ 语 å :senil 2 --^+}| + {5:·················ةيَّبِرَعَلا x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å :senil 2 --^+}| {1: ~}| {1: ~}| {1: ~}| @@ -1163,7 +1335,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {5:·················ةيَّبِرَعَلا x̎͂̀̂͛͛ 语 å :senil 2 --^+}| + {5:·················ﺔﻴَّﺑِﺮَﻌَﻟﺍ x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å :senil 2 --^+}| {1: ~}| {1: ~}| {1: ~}| @@ -1175,7 +1347,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - {5:·················ةيَّبِرَعَلا x̎͂̀̂͛͛ 语 å :senil 2 --^+}| + {5:·················ﺔﻴَّﺑِﺮَﻌَﻟﺍ x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å :senil 2 --^+}| {1: ~}| {1: ~}| {1: ~}| @@ -1199,7 +1371,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - ﺔﻴَّﺑِﺮَﻌَ^ﻟﺍ x̎͂̀̂͛͛ 语 å| + ﺔﻴَّﺑِﺮَﻌَ^ﻟﺍ x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å| txet eröm| {1: ~}| {1: ~}| @@ -1211,7 +1383,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - ﺔﻴَّﺑِﺮَﻌَ^ﻟﺍ x̎͂̀̂͛͛ 语 å| + ﺔﻴَّﺑِﺮَﻌَ^ﻟﺍ x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å| txet eröm| {1: ~}| {1: ~}| @@ -1235,7 +1407,7 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - ةيَّبِرَعَ^لا x̎͂̀̂͛͛ 语 å| + ةيَّبِرَعَ^لا x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å| txet eröm| {1: ~}| {1: ~}| @@ -1247,7 +1419,7 @@ describe("folded lines", function() ]]) else screen:expect([[ - ةيَّبِرَعَ^لا x̎͂̀̂͛͛ 语 å| + ةيَّبِرَعَ^لا x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢ 语 å| txet eröm| {1: ~}| {1: ~}| @@ -1854,21 +2026,19 @@ describe("folded lines", function() end end) - it('fold attached virtual lines are drawn correctly #21837', function() + it('fold attached virtual lines are drawn and scrolled 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", ""}}} }) - ]]) + local ns = meths.create_namespace('ns') + meths.buf_set_extmark(0, ns, 0, 0, { virt_lines_above = true, virt_lines = {{{"virt_line above line 1", ""}}} }) + meths.buf_set_extmark(0, ns, 1, 0, { virt_lines = {{{"virt_line below line 2", ""}}} }) + meths.buf_set_extmark(0, ns, 2, 0, { virt_lines_above = true, virt_lines = {{{"virt_line above line 3", ""}}} }) + meths.buf_set_extmark(0, ns, 3, 0, { virt_lines = {{{"virt_line below line 4", ""}}} }) if multigrid then - screen:expect([[ + screen:expect{grid=[[ ## grid 1 [2:---------------------------------------------]| [2:---------------------------------------------]| @@ -1888,7 +2058,9 @@ describe("folded lines", function() {1:~ }| ## grid 3 | - ]]) + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 5, curline = 0, curcol = 0, linecount = 4, sum_scroll_delta = 0}; + }} else screen:expect([[ {5:^+-- 2 lines: line 1·························}| @@ -1904,7 +2076,7 @@ describe("folded lines", function() feed('jzfj') if multigrid then - screen:expect([[ + screen:expect{grid=[[ ## grid 1 [2:---------------------------------------------]| [2:---------------------------------------------]| @@ -1924,7 +2096,9 @@ describe("folded lines", function() {1:~ }| ## grid 3 | - ]]) + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 5, curline = 2, curcol = 0, linecount = 4, sum_scroll_delta = 0}; + }} else screen:expect([[ {5:+-- 2 lines: line 1·························}| @@ -1941,7 +2115,7 @@ describe("folded lines", function() feed('kzo<C-Y>') funcs.setline(5, 'line 5') if multigrid then - screen:expect([[ + screen:expect{grid=[[ ## grid 1 [2:---------------------------------------------]| [2:---------------------------------------------]| @@ -1961,7 +2135,9 @@ describe("folded lines", function() {1:~ }| ## grid 3 | - ]]) + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 0, curcol = 0, linecount = 5, sum_scroll_delta = -1}; + }} else screen:expect([[ virt_line above line 1 | @@ -1974,6 +2150,940 @@ describe("folded lines", function() | ]]) end + + meths.input_mouse('left', 'press', '', multigrid and 2 or 0, 4, 0) + eq({ + screencol = 1, + screenrow = 5, + winid = 1000, + wincol = 1, + winrow = 5, + line = 3, + column = 1, + coladd = 0, + }, funcs.getmousepos()) + + meths.buf_set_extmark(0, ns, 1, 0, { virt_lines = {{{"more virt_line below line 2", ""}}} }) + feed('G<C-E>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + line 1 | + line 2 | + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 0}; + }} + else + screen:expect([[ + line 1 | + line 2 | + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + | + ]]) + end + + feed('<C-E>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + line 2 | + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 1, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 1}; + }} + else + screen:expect([[ + line 2 | + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + | + ]]) + end + + feed('<C-E>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 2, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 2}; + }} + else + screen:expect([[ + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + + feed('<C-E>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 2, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 3}; + }} + else + screen:expect([[ + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + + feed('<C-E>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 2, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 4}; + }} + else + screen:expect([[ + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + + feed('<C-E>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 4, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 5}; + }} + else + screen:expect([[ + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + + feed('3<C-Y>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 2, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 2}; + }} + else + screen:expect([[ + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^line 5 | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + + meths.input_mouse('left', 'press', '3', multigrid and 2 or 0, 3, 0) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^l{16:ine 5} | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL LINE --} | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 2, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 2}; + }} + else + screen:expect([[ + virt_line below line 2 | + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^l{16:ine 5} | + {1:~ }| + {1:~ }| + {1:~ }| + {11:-- VISUAL LINE --} | + ]]) + end + + meths.input_mouse('left', 'drag', '3', multigrid and 2 or 0, 7, 0) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^l{16:ine 5} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL LINE --} | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 2, botline = 6, curline = 4, curcol = 0, linecount = 5, sum_scroll_delta = 3}; + }} + else + screen:expect([[ + more virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + ^l{16:ine 5} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {11:-- VISUAL LINE --} | + ]]) + end + + meths.input_mouse('left', 'drag', '3', multigrid and 2 or 0, 7, 5) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {5:+-- 2 lines: line 3·························}| + {16:line }^5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL LINE --} | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 2, botline = 6, curline = 4, curcol = 5, linecount = 5, sum_scroll_delta = 4}; + }} + else + screen:expect([[ + {5:+-- 2 lines: line 3·························}| + {16:line }^5 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {11:-- VISUAL LINE --} | + ]]) + end + + feed('<Esc>gg') + command('botright 1split | wincmd w') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + {3:[No Name] [+] }| + [4:---------------------------------------------]| + {2:[No Name] [+] }| + [3:---------------------------------------------]| + ## grid 2 + ^line 1 | + line 2 | + virt_line below line 2 | + more virt_line below line 2 | + ## grid 3 + | + ## grid 4 + line 1 | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 5, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 5, sum_scroll_delta = 0}; + }} + else + screen:expect([[ + ^line 1 | + line 2 | + virt_line below line 2 | + more virt_line below line 2 | + {3:[No Name] [+] }| + line 1 | + {2:[No Name] [+] }| + | + ]]) + end + + feed('<C-Y>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + {3:[No Name] [+] }| + [4:---------------------------------------------]| + {2:[No Name] [+] }| + [3:---------------------------------------------]| + ## grid 2 + virt_line above line 1 | + ^line 1 | + line 2 | + virt_line below line 2 | + ## grid 3 + | + ## grid 4 + line 1 | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 5, sum_scroll_delta = -1}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 5, sum_scroll_delta = 0}; + }} + else + screen:expect([[ + virt_line above line 1 | + ^line 1 | + line 2 | + virt_line below line 2 | + {3:[No Name] [+] }| + line 1 | + {2:[No Name] [+] }| + | + ]]) + end + end) + + it('Folded and Visual highlights are combined #19691', function() + command('hi! Visual guibg=Red') + insert([[ + " foofoofoofoofoofoo + " 口 {{{1 + set nocp + " }}}1 + " barbarbarbarbarbar + " 口 {{{1 + set foldmethod=marker + " }}}1 + " bazbazbazbazbazbaz]]) + feed('gg') + command('source') + feed('<C-V>G15l') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {14:" foofoofoofoofo}ofoo | + {15:+-- 3 lines: " }{5:口···························}| + {14:" barbarbarbarba}rbar | + {15:+-- 3 lines: " }{5:口···························}| + {14:" bazbazbazbazb}^azbaz | + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL BLOCK --} | + ]]) + else + screen:expect([[ + {14:" foofoofoofoofo}ofoo | + {15:+-- 3 lines: " }{5:口···························}| + {14:" barbarbarbarba}rbar | + {15:+-- 3 lines: " }{5:口···························}| + {14:" bazbazbazbazb}^azbaz | + {1:~ }| + {1:~ }| + {11:-- VISUAL BLOCK --} | + ]]) + end + + feed('l') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {14:" foofoofoofoofoo}foo | + {15:+-- 3 lines: " 口}{5:···························}| + {14:" barbarbarbarbar}bar | + {15:+-- 3 lines: " 口}{5:···························}| + {14:" bazbazbazbazba}^zbaz | + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL BLOCK --} | + ]]) + else + screen:expect([[ + {14:" foofoofoofoofoo}foo | + {15:+-- 3 lines: " 口}{5:···························}| + {14:" barbarbarbarbar}bar | + {15:+-- 3 lines: " 口}{5:···························}| + {14:" bazbazbazbazba}^zbaz | + {1:~ }| + {1:~ }| + {11:-- VISUAL BLOCK --} | + ]]) + end + + feed('l') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {14:" foofoofoofoofoof}oo | + {15:+-- 3 lines: " 口}{5:···························}| + {14:" barbarbarbarbarb}ar | + {15:+-- 3 lines: " 口}{5:···························}| + {14:" bazbazbazbazbaz}^baz | + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL BLOCK --} | + ]]) + else + screen:expect([[ + {14:" foofoofoofoofoof}oo | + {15:+-- 3 lines: " 口}{5:···························}| + {14:" barbarbarbarbarb}ar | + {15:+-- 3 lines: " 口}{5:···························}| + {14:" bazbazbazbazbaz}^baz | + {1:~ }| + {1:~ }| + {11:-- VISUAL BLOCK --} | + ]]) + end + + feed('2l') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {14:" foofoofoofoofoofoo} | + {15:+-- 3 lines: " 口··}{5:·························}| + {14:" barbarbarbarbarbar} | + {15:+-- 3 lines: " 口··}{5:·························}| + {14:" bazbazbazbazbazba}^z | + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL BLOCK --} | + ]]) + else + screen:expect([[ + {14:" foofoofoofoofoofoo} | + {15:+-- 3 lines: " 口··}{5:·························}| + {14:" barbarbarbarbarbar} | + {15:+-- 3 lines: " 口··}{5:·························}| + {14:" bazbazbazbazbazba}^z | + {1:~ }| + {1:~ }| + {11:-- VISUAL BLOCK --} | + ]]) + end + + feed('O16l') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + " foofoofoofoofo{14:ofoo} | + {5:+-- 3 lines: " }{15:口··}{5:·························}| + " barbarbarbarba{14:rbar} | + {5:+-- 3 lines: " }{15:口··}{5:·························}| + " bazbazbazbazba^z{14:baz} | + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL BLOCK --} | + ]]) + else + screen:expect([[ + " foofoofoofoofo{14:ofoo} | + {5:+-- 3 lines: " }{15:口··}{5:·························}| + " barbarbarbarba{14:rbar} | + {5:+-- 3 lines: " }{15:口··}{5:·························}| + " bazbazbazbazba^z{14:baz} | + {1:~ }| + {1:~ }| + {11:-- VISUAL BLOCK --} | + ]]) + end + + feed('l') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + " foofoofoofoofoo{14:foo} | + {5:+-- 3 lines: " }{15:口··}{5:·························}| + " barbarbarbarbar{14:bar} | + {5:+-- 3 lines: " }{15:口··}{5:·························}| + " bazbazbazbazbaz^b{14:az} | + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL BLOCK --} | + ]]) + else + screen:expect([[ + " foofoofoofoofoo{14:foo} | + {5:+-- 3 lines: " }{15:口··}{5:·························}| + " barbarbarbarbar{14:bar} | + {5:+-- 3 lines: " }{15:口··}{5:·························}| + " bazbazbazbazbaz^b{14:az} | + {1:~ }| + {1:~ }| + {11:-- VISUAL BLOCK --} | + ]]) + end + end) + + it('do not show search or match highlight #24084', function() + insert([[ + line 1 + line 2 + line 3 + line 4]]) + command('2,3fold') + feed('/line') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {2:line} 1 | + {5:+-- 2 lines: line 2·························}| + {6:line} 4 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + /line^ | + ]]) + else + screen:expect([[ + {2:line} 1 | + {5:+-- 2 lines: line 2·························}| + {6:line} 4 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + /line^ | + ]]) + end + feed('<Esc>') + funcs.matchadd('Search', 'line') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {6:line} 1 | + {5:+-- 2 lines: line 2·························}| + {6:line} ^4 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {6:line} 1 | + {5:+-- 2 lines: line 2·························}| + {6:line} ^4 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + end) + + it('support foldtext with virtual text format', function() + screen:try_resize(30, 7) + insert(content1) + command("hi! CursorLine guibg=NONE guifg=Red gui=NONE") + command('hi F0 guibg=Red guifg=Black') + command('hi F1 guifg=White') + meths.set_option_value('cursorline', true, {}) + meths.set_option_value('foldcolumn', '4', {}) + meths.set_option_value('foldtext', '[' + .. '["▶", ["F0", "F1"]], ' + .. '[v:folddashes], ' + .. '["\t", "Search"], ' + .. '[getline(v:foldstart), "NonText"]]', {}) + + command('3,4fold') + command('5,6fold') + command('2,6fold') + if multigrid then + screen:expect([[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [3:------------------------------]| + ## grid 2 + {7: }This is a | + {7:+ }{4:^▶}{13:-}{17: }{18:valid English}{13:·····}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {7: }This is a | + {7:+ }{4:^▶}{13:-}{17: }{18:valid English}{13:·····}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + eq('▶-\tvalid English', funcs.foldtextresult(2)) + + feed('zo') + if multigrid then + screen:expect([[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [3:------------------------------]| + ## grid 2 + {7: }This is a | + {7:- }valid English | + {7:│+ }{4:▶}{5:--}{19: }{18:sentence composed }| + {7:│+ }{4:^▶}{13:--}{17: }{18:in his cave.}{13:······}| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {7: }This is a | + {7:- }valid English | + {7:│+ }{4:▶}{5:--}{19: }{18:sentence composed }| + {7:│+ }{4:^▶}{13:--}{17: }{18:in his cave.}{13:······}| + {1:~ }| + {1:~ }| + | + ]]) + end + eq('▶--\tsentence composed by', funcs.foldtextresult(3)) + eq('▶--\tin his cave.', funcs.foldtextresult(5)) + + command('hi! Visual guibg=Red') + feed('V2k') + if multigrid then + screen:expect([[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [3:------------------------------]| + ## grid 2 + {7: }This is a | + {7:- }^v{14:alid English} | + {7:│+ }{4:▶}{15:--}{19: }{20:sentence composed }| + {7:│+ }{4:▶}{15:--}{19: }{20:in his cave.}{15:······}| + {1:~ }| + {1:~ }| + ## grid 3 + {11:-- VISUAL LINE --} | + ]]) + else + screen:expect([[ + {7: }This is a | + {7:- }^v{14:alid English} | + {7:│+ }{4:▶}{15:--}{19: }{20:sentence composed }| + {7:│+ }{4:▶}{15:--}{19: }{20:in his cave.}{15:······}| + {1:~ }| + {1:~ }| + {11:-- VISUAL LINE --} | + ]]) + end + + meths.set_option_value('rightleft', true, {}) + if multigrid then + screen:expect([[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [3:------------------------------]| + ## grid 2 + a si sihT{7: }| + {14:hsilgnE dila}^v{7: -}| + {20: desopmoc ecnetnes}{19: }{15:--}{4:▶}{7: +│}| + {15:······}{20:.evac sih ni}{19: }{15:--}{4:▶}{7: +│}| + {1: ~}| + {1: ~}| + ## grid 3 + {11:-- VISUAL LINE --} | + ]]) + else + screen:expect([[ + a si sihT{7: }| + {14:hsilgnE dila}^v{7: -}| + {20: desopmoc ecnetnes}{19: }{15:--}{4:▶}{7: +│}| + {15:······}{20:.evac sih ni}{19: }{15:--}{4:▶}{7: +│}| + {1: ~}| + {1: ~}| + {11:-- VISUAL LINE --} | + ]]) + end end) end @@ -1984,26 +3094,4 @@ describe("folded lines", function() describe('without ext_multigrid', function() with_ext_multigrid(false) end) - - it('no folds remains if :delete makes buffer empty #19671', function() - funcs.setline(1, {'foo', 'bar', 'baz'}) - command('2,3fold') - command('%delete') - eq(0, funcs.foldlevel(1)) - end) - - it('multibyte fold markers work #20438', function() - 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 288c2a214f..7776e024b0 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -8,6 +8,7 @@ local feed_command, eq = helpers.feed_command, helpers.eq local curbufmeths = helpers.curbufmeths local funcs = helpers.funcs local meths = helpers.meths +local exec_lua = helpers.exec_lua describe('colorscheme compatibility', function() before_each(function() @@ -376,7 +377,6 @@ describe('highlight', function() -- Vertical cursor: highlights char-at-cursor. #8983 command('set guicursor=a:block-blinkon175') - feed('<esc>gg$vhhh') screen:expect([[ line1 foo{1:^ bar} | | @@ -427,7 +427,7 @@ describe('highlight', function() ^ | {2:~ }| | - ]],{ + ]], { [1] = {strikethrough = true}, [2] = {bold = true, foreground = Screen.colors.Blue1}, }) @@ -516,7 +516,7 @@ describe('highlight', function() {1:neovim} tabbed^ | {0:~ }| {5:-- INSERT --} | - ]],{ + ]], { [0] = {bold=true, foreground=Screen.colors.Blue}, [1] = {background = Screen.colors.Yellow, foreground = Screen.colors.Red, special = Screen.colors.Red}, @@ -527,6 +527,41 @@ describe('highlight', function() }) end) + + it("'diff', syntax and extmark #23722", function() + local screen = Screen.new(25,10) + screen:attach() + exec([[ + new + call setline(1, ['', '01234 6789']) + windo diffthis + wincmd w + syn match WarningMsg "^.*$" + call nvim_buf_add_highlight(0, -1, 'ErrorMsg', 1, 2, 8) + ]]) + screen:expect([[ + {1: }^ | + {1: }{2:01}{3:234 67}{2:89}{5: }| + {4:~ }| + {4:~ }| + {7:[No Name] [+] }| + {1: } | + {1: }{6:-----------------------}| + {4:~ }| + {8:[No Name] }| + | + ]], { + [0] = {Screen.colors.WebGray, foreground = Screen.colors.DarkBlue}, + [1] = {background = Screen.colors.Grey, foreground = Screen.colors.Blue4}, + [2] = {foreground = Screen.colors.Red, background = Screen.colors.LightBlue}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.LightBlue}, + [4] = {bold = true, foreground = Screen.colors.Blue}, + [5] = {background = Screen.colors.LightBlue}, + [6] = {bold = true, background = Screen.colors.LightCyan, foreground = Screen.colors.Blue1}, + [7] = {reverse = true, bold = true}, + [8] = {reverse = true}, + }) + end) end) describe("'listchars' highlight", function() @@ -1412,10 +1447,10 @@ describe('ColorColumn highlight', function() [3] = {foreground = Screen.colors.Brown}, -- LineNr [4] = {foreground = Screen.colors.Brown, bold = true}, -- CursorLineNr [5] = {foreground = Screen.colors.Blue, bold = true}, -- NonText - -- NonText and ColorColumn [6] = {foreground = Screen.colors.Blue, background = Screen.colors.LightRed, bold = true}, [7] = {reverse = true, bold = true}, -- StatusLine [8] = {reverse = true}, -- StatusLineNC + [9] = {background = Screen.colors.Grey90, foreground = Screen.colors.Red}, }) screen:attach() end) @@ -1501,6 +1536,25 @@ describe('ColorColumn highlight', function() | ]]) end) + + it('is combined with low-priority CursorLine highlight #23016', function() + screen:try_resize(40, 2) + command('set colorcolumn=30 cursorline') + screen:expect([[ + {2:^ }{1: }{2: }| + | + ]]) + command('hi clear ColorColumn') + screen:expect([[ + {2:^ }| + | + ]]) + command('hi ColorColumn guifg=Red') + screen:expect([[ + {2:^ }{9: }{2: }| + | + ]]) + end) end) describe("MsgSeparator highlight and msgsep fillchar", function() @@ -1812,6 +1866,31 @@ describe("'winhighlight' highlight", function() ]]) end) + it('works for background color in rightleft window #22640', function() + -- Use a wide screen to also check that this doesn't overflow linebuf_attr. + screen:try_resize(80, 6) + insert('aa') + command('setlocal rightleft') + command('setlocal winhl=Normal:Background1') + screen:expect([[ + {1: ^aa}| + {2: ~}| + {2: ~}| + {2: ~}| + {2: ~}| + | + ]]) + command('botright vsplit') + screen:expect([[ + {1: aa│ ^aa}| + {2: ~}{1:│}{2: ~}| + {2: ~}{1:│}{2: ~}| + {2: ~}{1:│}{2: ~}| + {4:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + end) + it('handles undefined groups', function() command("set winhl=Normal:Background1") screen:expect([[ @@ -2408,6 +2487,23 @@ describe("'winhighlight' highlight", function() | ]]} end) + + it('can link to empty highlight group', function() + command 'hi NormalNC guibg=Red' -- czerwone time + command 'set winhl=NormalNC:Normal' + command 'split' + + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {3:[No Name] }| + | + {0:~ }| + {4:[No Name] }| + | + ]]} + end) end) describe('highlight namespaces', function() @@ -2427,6 +2523,8 @@ describe('highlight namespaces', function() [6] = {bold = true, reverse = true}; [7] = {reverse = true}; [8] = {foreground = Screen.colors.Gray20}; + [9] = {foreground = Screen.colors.Blue}; + [10] = {bold = true, foreground = Screen.colors.SeaGreen}; } ns1 = meths.create_namespace 'grungy' @@ -2546,4 +2644,34 @@ describe('highlight namespaces', function() | ]]} end) + + it('winhl does not accept invalid value #24586', function() + local res = exec_lua([[ + local curwin = vim.api.nvim_get_current_win() + vim.api.nvim_command("set winhl=Normal:Visual") + local _, msg = pcall(vim.api.nvim_command,"set winhl='Normal:Wrong'") + return { msg, vim.wo[curwin].winhl } + ]]) + eq({ + "Vim(set):E5248: Invalid character in group name", + "Normal:Visual", + },res) + end) + + it('Normal in set_hl #25474', function() + meths.set_hl(0, 'Normal', {bg='#333333'}) + command('highlight Ignore') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {6: }| + | + Ignore {8:xxx} {9:ctermf}| + {9:g=}15 {9:guifg=}| + bg | + {10:Press ENTER or type comma}| + {10:nd to continue}^ | + ]]} + end) end) diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 6fbf9b72c8..3ee67a710c 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -2,7 +2,6 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear = helpers.clear local command = helpers.command -local curbufmeths = helpers.curbufmeths local eq = helpers.eq local eval = helpers.eval local feed_command = helpers.feed_command @@ -175,11 +174,14 @@ describe(":substitute, 'inccommand' preserves", function() it("'undolevels' (inccommand="..case..")", function() feed_command("set undolevels=139") feed_command("setlocal undolevels=34") + feed_command("split") -- Show the buffer in multiple windows feed_command("set inccommand=" .. case) insert("as") - feed(":%s/as/glork/<enter>") - eq(meths.get_option('undolevels'), 139) - eq(curbufmeths.get_option('undolevels'), 34) + feed(":%s/as/glork/") + poke_eventloop() + feed("<enter>") + eq(meths.get_option_value('undolevels', {scope='global'}), 139) + eq(meths.get_option_value('undolevels', {buf=0}), 34) end) end @@ -745,10 +747,11 @@ describe(":substitute, 'inccommand' preserves undo", function() end) describe(":substitute, inccommand=split", function() - local screen = Screen.new(30,15) + local screen before_each(function() clear() + screen = Screen.new(30,15) common_setup(screen, "split", default_text .. default_text) end) @@ -1191,7 +1194,7 @@ describe(":substitute, inccommand=split", function() it("deactivates if 'redrawtime' is exceeded #5602", function() -- prevent redraws from 'incsearch' - meths.set_option('incsearch', false) + meths.set_option_value('incsearch', false, {}) -- Assert that 'inccommand' is ENABLED initially. eq("split", eval("&inccommand")) -- Set 'redrawtime' to minimal value, to ensure timeout is triggered. @@ -1413,10 +1416,11 @@ describe(":substitute, inccommand=split", function() end) describe("inccommand=nosplit", function() - local screen = Screen.new(20,10) + local screen before_each(function() clear() + screen = Screen.new(20,10) common_setup(screen, "nosplit", default_text .. default_text) end) @@ -1644,11 +1648,12 @@ describe("inccommand=nosplit", function() end) describe(":substitute, 'inccommand' with a failing expression", function() - local screen = Screen.new(20,10) + local screen local cases = { "", "split", "nosplit" } local function refresh(case) clear() + screen = Screen.new(20,10) common_setup(screen, case, default_text) end @@ -1717,7 +1722,7 @@ describe("'inccommand' and :cnoremap", function() local function refresh(case, visual) clear() - screen = visual and Screen.new(50,10) or nil + screen = visual and Screen.new(80,10) or nil common_setup(screen, case, default_text) end @@ -2127,9 +2132,10 @@ describe("'inccommand' with 'gdefault'", function() end) describe(":substitute", function() - local screen = Screen.new(30,15) + local screen before_each(function() clear() + screen = Screen.new(30,15) end) it("inccommand=split, highlights multiline substitutions", function() @@ -2335,8 +2341,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=split, substitutions of different length", - function() + it("inccommand=split, substitutions of different length", function() common_setup(screen, "split", "T T123 T2T TTT T090804\nx") feed(":%s/T\\([0-9]\\+\\)/\\1\\1/g") @@ -2462,16 +2467,14 @@ describe(":substitute", function() end) it("inccommand=split, contraction of two subsequent NL chars", function() - -- luacheck: push ignore 611 local text = [[ AAA AA - + BBB BB - + CCC CC - + ]] - -- luacheck: pop -- This used to crash, but more than 20 highlight entries are required -- to reproduce it (so that the marktree has multiple nodes) @@ -2498,16 +2501,14 @@ describe(":substitute", function() end) it("inccommand=nosplit, contraction of two subsequent NL chars", function() - -- luacheck: push ignore 611 local text = [[ AAA AA - + BBB BB - + CCC CC - + ]] - -- luacheck: pop common_setup(screen, "nosplit", string.rep(text,10)) feed(":%s/\\n\\n/<c-v><c-m>/g") @@ -2872,8 +2873,8 @@ it(':substitute with inccommand during :terminal activity', function() return end retry(2, 40000, function() - local screen = Screen.new(30,15) clear() + local screen = Screen.new(30,15) command("set cmdwinheight=3") feed(([[:terminal "%s" REP 5000 xxx<cr>]]):format(testprg('shell-test'))) @@ -2886,14 +2887,15 @@ it(':substitute with inccommand during :terminal activity', function() feed('gg') feed(':%s/foo/ZZZ') sleep(20) -- Allow some terminal activity. - helpers.poke_eventloop() + poke_eventloop() + screen:sleep(0) screen:expect_unchanged() end) end) it(':substitute with inccommand, timer-induced :redraw #9777', function() - local screen = Screen.new(30,12) clear() + local screen = Screen.new(30,12) command('set cmdwinheight=3') command('call timer_start(10, {-> execute("redraw")}, {"repeat":-1})') command('call timer_start(10, {-> execute("redrawstatus")}, {"repeat":-1})') @@ -2919,15 +2921,24 @@ it(':substitute with inccommand, timer-induced :redraw #9777', function() end) it(':substitute with inccommand, allows :redraw before first separator is typed #18857', function() - local screen = Screen.new(30,6) clear() + local screen = Screen.new(30,6) common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz') command('hi! link NormalFloat CursorLine') local float_buf = meths.create_buf(false, true) meths.open_win(float_buf, false, { relative = 'editor', height = 1, width = 5, row = 3, col = 0, focusable = false, }) - feed(':%s') + feed(':') + screen:expect([[ + foo bar baz | + bar baz fox | + bar foo baz | + {16: }{15: }| + {15:~ }| + :^ | + ]]) + feed('%s') screen:expect([[ foo bar baz | bar baz fox | @@ -2949,8 +2960,8 @@ it(':substitute with inccommand, allows :redraw before first separator is typed end) it(':substitute with inccommand, does not crash if range contains invalid marks', function() - local screen = Screen.new(30, 6) clear() + local screen = Screen.new(30, 6) common_setup(screen, 'split', 'test') feed([[:'a,'bs]]) screen:expect([[ @@ -2975,8 +2986,8 @@ it(':substitute with inccommand, does not crash if range contains invalid marks' end) it(':substitute with inccommand, no unnecessary redraw if preview is not shown', function() - local screen = Screen.new(60, 6) clear() + local screen = Screen.new(60, 6) common_setup(screen, 'split', 'test') feed(':ls<CR>') screen:expect([[ @@ -3028,8 +3039,8 @@ it(':substitute with inccommand, no unnecessary redraw if preview is not shown', end) it(":substitute doesn't crash with inccommand, if undo is empty #12932", function() - local screen = Screen.new(10,5) clear() + local screen = Screen.new(10,5) command('set undolevels=-1') common_setup(screen, 'split', 'test') feed(':%s/test') @@ -3048,8 +3059,8 @@ it(":substitute doesn't crash with inccommand, if undo is empty #12932", functio end) it(':substitute with inccommand works properly if undo is not synced #20029', function() - local screen = Screen.new(30, 6) clear() + local screen = Screen.new(30, 6) common_setup(screen, 'nosplit', 'foo\nbar\nbaz') meths.set_keymap('x', '<F2>', '<Esc>`<Oaaaaa asdf<Esc>`>obbbbb asdf<Esc>V`<k:s/asdf/', {}) feed('gg0<C-V>lljj<F2>') @@ -3084,11 +3095,40 @@ it(':substitute with inccommand works properly if undo is not synced #20029', fu baz]]) end) +it(':substitute with inccommand does not unexpectedly change viewport #25697', function() + clear() + local screen = Screen.new(45, 5) + common_setup(screen, 'nosplit', long_multiline_text) + command('vnew | tabnew | tabclose') + screen:expect([[ + ^ │£ m n | + {15:~ }│t œ ¥ | + {15:~ }│ | + {11:[No Name] }{10:[No Name] [+] }| + | + ]]) + feed(':s/') + screen:expect([[ + │£ m n | + {15:~ }│t œ ¥ | + {15:~ }│ | + {11:[No Name] }{10:[No Name] [+] }| + :s/^ | + ]]) + feed('<Esc>') + screen:expect([[ + ^ │£ m n | + {15:~ }│t œ ¥ | + {15:~ }│ | + {11:[No Name] }{10:[No Name] [+] }| + | + ]]) +end) + it('long :%s/ with inccommand does not collapse cmdline', function() - local screen = Screen.new(10,5) clear() - common_setup(screen) - command('set inccommand=nosplit') + local screen = Screen.new(10,5) + common_setup(screen, 'nosplit') feed(':%s/AAAAAAA', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A') screen:expect([[ @@ -3100,6 +3140,21 @@ it('long :%s/ with inccommand does not collapse cmdline', function() ]]) end) +it("with 'inccommand' typing invalid `={expr}` does not show error", function() + clear() + local screen = Screen.new(30, 6) + common_setup(screen, 'nosplit') + feed(':edit `=`') + screen:expect([[ + | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + :edit `=`^ | + ]]) +end) + it("with 'inccommand' typing :filter doesn't segfault or leak memory #19057", function() clear() common_setup(nil, 'nosplit') @@ -3112,3 +3167,31 @@ it("with 'inccommand' typing :filter doesn't segfault or leak memory #19057", fu feed('i') assert_alive() end) + +it("'inccommand' cannot be changed during preview #23136", function() + clear() + local screen = Screen.new(30, 6) + common_setup(screen, 'nosplit', 'foo\nbar\nbaz') + source([[ + function! IncCommandToggle() + let prev = &inccommand + + if &inccommand ==# 'split' + set inccommand=nosplit + elseif &inccommand ==# 'nosplit' + set inccommand=split + elseif &inccommand ==# '' + set inccommand=nosplit + else + throw 'unknown inccommand' + endif + + return " \<BS>" + endfun + + cnoremap <expr> <C-E> IncCommandToggle() + ]]) + + feed(':%s/foo/bar<C-E><C-E><C-E>') + assert_alive() +end) diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua index 43e9b94feb..da7508fad1 100644 --- a/test/functional/ui/inccommand_user_spec.lua +++ b/test/functional/ui/inccommand_user_spec.lua @@ -239,7 +239,8 @@ describe("'inccommand' for user commands", function() [1] = {background = Screen.colors.Yellow1}, [2] = {foreground = Screen.colors.Blue1, bold = true}, [3] = {reverse = true}, - [4] = {reverse = true, bold = true} + [4] = {reverse = true, bold = true}, + [5] = {foreground = Screen.colors.Blue}, }) screen:attach() exec_lua(setup_replace_cmd) @@ -391,7 +392,7 @@ describe("'inccommand' for user commands", function() vim.api.nvim_create_user_command('Replace', function() end, { nargs = '*', preview = function() - vim.api.nvim_set_option('inccommand', 'split') + vim.api.nvim_set_option_value('inccommand', 'split', {}) return 2 end, }) @@ -401,6 +402,147 @@ describe("'inccommand' for user commands", function() feed('e') assert_alive() end) + + it('no crash when adding highlight after :substitute #21495', function() + command('set inccommand=nosplit') + exec_lua([[ + vim.api.nvim_create_user_command("Crash", function() end, { + preview = function(_, preview_ns, _) + vim.cmd("%s/text/cats/g") + vim.api.nvim_buf_add_highlight(0, preview_ns, "Search", 0, 0, -1) + return 1 + end, + }) + ]]) + feed(':C') + screen:expect([[ + {1: cats on line 1} | + more cats on line 2 | + oh no, even more cats | + will the cats ever stop | + oh well | + did the cats stop | + why won't it stop | + make the cats stop | + | + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + :C^ | + ]]) + assert_alive() + end) + + it('no crash if preview callback executes undo #20036', function() + command('set inccommand=nosplit') + exec_lua([[ + vim.api.nvim_create_user_command('Foo', function() end, { + nargs = '?', + preview = function(_, _, _) + vim.cmd.undo() + end, + }) + ]]) + + -- Clear undo history + command('set undolevels=-1') + feed('ggyyp') + command('set undolevels=1000') + + feed('yypp:Fo') + assert_alive() + feed('<Esc>:Fo') + assert_alive() + end) + + local function test_preview_break_undo() + command('set inccommand=nosplit') + exec_lua([[ + vim.api.nvim_create_user_command('Test', function() end, { + nargs = 1, + preview = function(opts, _, _) + vim.cmd('norm i' .. opts.args) + return 1 + end + }) + ]]) + feed(':Test a.a.a.a.') + screen:expect([[ + text on line 1 | + more text on line 2 | + oh no, even more text | + will the text ever stop | + oh well | + did the text stop | + why won't it stop | + make the text stop | + a.a.a.a. | + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + :Test a.a.a.a.^ | + ]]) + feed('<C-V><Esc>u') + screen:expect([[ + text on line 1 | + more text on line 2 | + oh no, even more text | + will the text ever stop | + oh well | + did the text stop | + why won't it stop | + make the text stop | + a.a.a. | + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + :Test a.a.a.a.{5:^[}u^ | + ]]) + feed('<Esc>') + screen:expect([[ + text on line 1 | + more text on line 2 | + oh no, even more text | + will the text ever stop | + oh well | + did the text stop | + why won't it stop | + make the text stop | + ^ | + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + | + ]]) + end + + describe('breaking undo chain in Insert mode works properly', function() + it('when using i_CTRL-G_u #20248', function() + command('inoremap . .<C-G>u') + test_preview_break_undo() + end) + + it('when setting &l:undolevels to itself #24575', function() + command('inoremap . .<Cmd>let &l:undolevels = &l:undolevels<CR>') + test_preview_break_undo() + end) + end) end) describe("'inccommand' with multiple buffers", function() diff --git a/test/functional/ui/linematch_spec.lua b/test/functional/ui/linematch_spec.lua index 697677aa67..ef47ea7ed0 100644 --- a/test/functional/ui/linematch_spec.lua +++ b/test/functional/ui/linematch_spec.lua @@ -779,6 +779,192 @@ something end) end) + describe('setup a diff with 2 files and set linematch:30', function() + before_each(function() + feed(':set diffopt+=linematch:30<cr>') + local f1 = [[ +// abc d +// d +// d + ]] + local f2 = [[ + +abc d +d + ]] + write_file(fname, f1, false) + write_file(fname_2, f2, false) + reread() + end) + + it('display results', function() + screen:expect([[ + {1: }{10: 1 }{4:^ }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 2 }{9:abc d }│{1: }{10: 1 }{8:// }{9:abc d }| + {1: }{10: 3 }{9:d }│{1: }{10: 2 }{8:// }{9:d }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 3 }{4:// d }| + {1: }{10: 4 } │{1: }{10: 4 } | + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {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 }| + :e | + ]]) + end) + end) + describe('setup a diff with 2 files and set linematch:30, with ignore white', function() + before_each(function() + feed(':set diffopt+=linematch:30<cr>:set diffopt+=iwhiteall<cr>') + local f1 = [[ +void testFunction () { + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + } + } +} + ]] + local f2 = [[ +void testFunction () { + // for (int j = 0; j < 10; i++) { + // } +} + ]] + write_file(fname, f1, false) + write_file(fname_2, f2, false) + reread() + end) + + it('display results', function() + screen:expect([[ + {1: }{10: 1 }^void testFunction () { │{1: }{10: 1 }void testFunction () { | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 2 }{4: for (int i = 0; i < 10; i++) { }| + {1: }{10: 2 }{9: }{8:// for (int j = 0; j < 10; i}{9:++) { }│{1: }{10: 3 }{9: }{8:for (int j = 0; j < 10; j}{9:++) { }| + {1: }{10: 3 }{9: }{8:// }{9:} }│{1: }{10: 4 }{9: } }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 5 }{4: } }| + {1: }{10: 4 }} │{1: }{10: 6 }} | + {1: }{10: 5 } │{1: }{10: 7 } | + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {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 }| + :e | + ]]) + end) + end) + describe('a diff that would result in multiple groups before grouping optimization', function() + before_each(function() + feed(':set diffopt+=linematch:30<cr>') + local f1 = [[ +!A +!B +!C + ]] + local f2 = [[ +?Z +?A +?B +?C +?A +?B +?B +?C + ]] + write_file(fname, f1, false) + write_file(fname_2, f2, false) + reread() + end) + + it('display results', function() + screen:expect([[ + {1: }{10: 1 }{4:^?Z }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 2 }{8:?}{9:A }│{1: }{10: 1 }{8:!}{9:A }| + {1: }{10: 3 }{8:?}{9:B }│{1: }{10: 2 }{8:!}{9:B }| + {1: }{10: 4 }{8:?}{9:C }│{1: }{10: 3 }{8:!}{9:C }| + {1: }{10: 5 }{4:?A }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 6 }{4:?B }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 7 }{4:?B }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 8 }{4:?C }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 9 } │{1: }{10: 4 } | + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {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 }| + :e | + ]]) + end) + end) + describe('a diff that would result in multiple groups before grouping optimization', function() + before_each(function() + feed(':set diffopt+=linematch:30<cr>') + local f1 = [[ +!A +!B +!C + ]] + local f2 = [[ +?A +?Z +?B +?C +?A +?B +?C +?C + ]] + write_file(fname, f1, false) + write_file(fname_2, f2, false) + reread() + end) + + it('display results', function() + screen:expect([[ + {1: }{10: 1 }{4:^?A }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 2 }{4:?Z }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 3 }{4:?B }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 4 }{4:?C }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 5 }{8:?}{9:A }│{1: }{10: 1 }{8:!}{9:A }| + {1: }{10: 6 }{8:?}{9:B }│{1: }{10: 2 }{8:!}{9:B }| + {1: }{10: 7 }{8:?}{9:C }│{1: }{10: 3 }{8:!}{9:C }| + {1: }{10: 8 }{4:?C }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 9 } │{1: }{10: 4 } | + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {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 }| + :e | + ]]) + end) + end) describe('setup a diff with 2 files and set linematch:10', function() before_each(function() feed(':set diffopt+=linematch:10<cr>') @@ -992,4 +1178,48 @@ describe('regressions', function() helpers.curbufmeths.set_lines(0, -1, false, { string.rep('a', 1010)..'world' }) helpers.exec 'windo diffthis' end) + + it("properly computes filler lines for hunks bigger than linematch limit", function() + clear() + feed(':set diffopt+=linematch:10<cr>') + screen = Screen.new(100, 20) + screen:attach() + local lines = {} + for i = 0, 29 do + lines[#lines + 1] = tostring(i) + end + helpers.curbufmeths.set_lines(0, -1, false, lines) + helpers.exec 'vnew' + helpers.curbufmeths.set_lines(0, -1, false, { '00', '29' }) + helpers.exec 'windo diffthis' + feed('<C-e>') + screen:expect{grid=[[ + {1: }{2:------------------------------------------------}│{1: }{3:^1 }| + {1: }{2:------------------------------------------------}│{1: }{3:2 }| + {1: }{2:------------------------------------------------}│{1: }{3:3 }| + {1: }{2:------------------------------------------------}│{1: }{3:4 }| + {1: }{2:------------------------------------------------}│{1: }{3:5 }| + {1: }{2:------------------------------------------------}│{1: }{3:6 }| + {1: }{2:------------------------------------------------}│{1: }{3:7 }| + {1: }{2:------------------------------------------------}│{1: }{3:8 }| + {1: }{2:------------------------------------------------}│{1: }{3:9 }| + {1: }{2:------------------------------------------------}│{1: }{3:10 }| + {1: }{2:------------------------------------------------}│{1: }{3:11 }| + {1: }{2:------------------------------------------------}│{1: }{3:12 }| + {1: }{2:------------------------------------------------}│{1: }{3:13 }| + {1: }{2:------------------------------------------------}│{1: }{3:14 }| + {1: }{2:------------------------------------------------}│{1: }{3:15 }| + {1: }{2:------------------------------------------------}│{1: }{3:16 }| + {1: }{2:------------------------------------------------}│{1: }{3:17 }| + {1: }29 │{1: }{3:18 }| + {4:[No Name] [+] }{5:[No Name] [+] }| + | + ]], attr_ids={ + [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Grey}; + [2] = {bold = true, background = Screen.colors.LightCyan, foreground = Screen.colors.Blue1}; + [3] = {background = Screen.colors.LightBlue}; + [4] = {reverse = true}; + [5] = {reverse = true, bold = true}; + }} + end) end) diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 3052a74f38..1d11a12af4 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -10,15 +10,19 @@ local async_meths = helpers.async_meths local test_build_dir = helpers.test_build_dir local nvim_prog = helpers.nvim_prog local exec = helpers.exec +local exec_capture = helpers.exec_capture local exc_exec = helpers.exc_exec local exec_lua = helpers.exec_lua local poke_eventloop = helpers.poke_eventloop local assert_alive = helpers.assert_alive local is_os = helpers.is_os local is_ci = helpers.is_ci +local funcs = helpers.funcs +local skip = helpers.skip describe('ui/ext_messages', function() local screen + local fname = 'Xtest_functional_ui_messages_spec' before_each(function() clear() @@ -38,7 +42,7 @@ describe('ui/ext_messages', function() }) end) after_each(function() - os.remove('Xtest') + os.remove(fname) end) it('msg_clear follows msg_show kind of confirm', function() @@ -123,7 +127,7 @@ describe('ui/ext_messages', function() feed('nq') -- kind=wmsg (editing readonly file) - command('write Xtest') + command('write ' .. fname) command('set readonly nohls') feed('G$x') screen:expect{grid=[[ @@ -329,6 +333,36 @@ describe('ui/ext_messages', function() ]]} end) + it(':echoerr multiline', function() + exec_lua([[vim.g.multi = table.concat({ "bork", "fail" }, "\n")]]) + feed(':echoerr g:multi<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "bork\nfail", 2 }}, + kind = "echoerr" + }}} + + feed(':messages<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "Press ENTER or type command to continue", 4 }}, + kind = "return_prompt" + }}, msg_history={{ + content = {{ "bork\nfail", 2 }}, + kind = "echoerr" + }}} + end) + it('shortmess-=S', function() command('set shortmess-=S') feed('iline 1\nline 2<esc>') @@ -474,8 +508,7 @@ describe('ui/ext_messages', function() ]], msg_history={{ content = {{ "stuff" }}, kind = "echomsg", - }}, showmode={{ "-- INSERT --", 3 }}, - messages={{ + }}, messages={{ content = {{ "Press ENTER or type command to continue", 4}}, kind = "return_prompt" }}} @@ -801,6 +834,19 @@ stack traceback: end} end) + it('supports multiline messages for :map', function() + command('mapclear') + command('nmap Y y$') + command('nmap Q @@') + command('nnoremap j k') + feed(':map<cr>') + + screen:expect{messages={{ + content = {{ "\nn Q @@\nn Y y$\nn j " }, { "*", 5 }, { " k" }}, + kind = '' + }}} + end) + it('wildmode=list', function() screen:try_resize(25, 7) screen:set_option('ext_popupmenu', false) @@ -910,9 +956,9 @@ stack traceback: end) it('does not truncate messages', function() - command('write Xtest') + command('write '.. fname) screen:expect({messages={ - {content = { { '"Xtest" [New] 0L, 0B written' } }, kind = "" } + {content = { { string.format('"%s" [New] 0L, 0B written', fname) } }, kind = "" } }}) end) end) @@ -985,7 +1031,7 @@ describe('ui/builtin messages', function() -- screen size doesn't affect internal output #10285 eq('ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red', - meths.exec("hi ErrorMsg", true)) + exec_capture("hi ErrorMsg")) end) it(':syntax list langGroup output', function() @@ -1024,10 +1070,57 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim match /\<endif\s\+".*$/ms=s+5,lc=5 contains=@vimCommentGroup,vimCommentString match /\<else\s\+".*$/ms=s+4,lc=4 contains=@vimCommentGroup,vimCommentString links to Comment]], - meths.exec('syntax list vimComment', true)) + exec_capture('syntax list vimComment')) -- luacheck: pop end) + it('no empty line after :silent #12099', function() + exec([[ + func T1() + silent !echo + echo "message T1" + endfunc + func T2() + silent lua print("lua message") + echo "message T2" + endfunc + func T3() + silent call nvim_out_write("api message\n") + echo "message T3" + endfunc + ]]) + feed(':call T1()<CR>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + message T1 | + ]]} + feed(':call T2()<CR>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + message T2 | + ]]} + feed(':call T3()<CR>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + message T3 | + ]]} + end) + it('supports ruler with laststatus=0', function() command("set ruler laststatus=0") screen:expect{grid=[[ @@ -1232,17 +1325,54 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim ]]) end) - it('echo messages are shown correctly when getchar() immediately follows', function() - feed([[:echo 'foo' | echo 'bar' | call getchar()<CR>]]) - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {3: }| - foo | - bar^ | - ]]) + describe('echo messages are shown when immediately followed by', function() + --- @param to_block string command to cause a blocking wait + --- @param to_unblock number|string number: timeout for blocking screen + --- string: keys to stop the blocking wait + local function test_flush_before_block(to_block, to_unblock) + local timeout = type(to_unblock) == 'number' and to_unblock or nil + exec(([[ + func PrintAndWait() + echon "aaa\nbbb" + %s + echon "\nccc" + endfunc + ]]):format(to_block)) + feed(':call PrintAndWait()<CR>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {3: }| + aaa | + bbb^ | + ]], timeout=timeout} + if type(to_unblock) == 'string' then + feed(to_unblock) + end + screen:expect{grid=[[ + | + {1:~ }| + {3: }| + aaa | + bbb | + ccc | + {4:Press ENTER or type command to continue}^ | + ]]} + end + + it('getchar()', function() + test_flush_before_block([[call getchar()]], 'k') + end) + + it('wait()', function() + test_flush_before_block([[call wait(300, '0')]], 100) + end) + + it('lua vim.wait()', function() + test_flush_before_block([[lua vim.wait(300, function() end)]], 100) + end) end) it('consecutive calls to win_move_statusline() work after multiline message #21014',function() @@ -1270,7 +1400,20 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim {1:~ }| | ]]) - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) + end) + + it('using nvim_echo in VimResized does not cause hit-enter prompt #26139', function() + command([[au VimResized * lua vim.api.nvim_echo({ { '123456' } }, true, {})]]) + screen:try_resize(60, 5) + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + eq({ mode = 'n', blocking = false }, meths.get_mode()) end) end) @@ -1322,7 +1465,7 @@ 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: +}}type :help news{5:<Enter>} to see changes in v{MATCH:%d+%.%d+}{1:{MATCH: +}}| {1:~ }| {MATCH:.*}| {MATCH:.*}| @@ -1363,7 +1506,7 @@ describe('ui/ext_messages', function() feed(":intro<cr>") screen:expect{grid=[[ - | + ^ | | | | @@ -1378,7 +1521,7 @@ 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: +}type :help news{5:<Enter>} to see changes in v{MATCH:%d+%.%d+ +}| | {MATCH:.*}| {MATCH:.*}| @@ -1917,6 +2060,7 @@ aliquip ex ea commodo consequat.]]) end) it('with :!cmd does not crash on resize', function() + skip(funcs.executable('sleep') == 0, 'missing "sleep" command') feed(':!sleep 1<cr>') screen:expect{grid=[[ | diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua index cf4eb034e0..e870d6f25f 100644 --- a/test/functional/ui/mode_spec.lua +++ b/test/functional/ui/mode_spec.lua @@ -44,7 +44,10 @@ describe('ui mode_change event', function() {0:~ }| | ]], mode="normal"} + end) + -- oldtest: Test_mouse_shape_after_failed_change() + it('is restored to Normal mode after failed "c"', function() screen:try_resize(50, 4) command('set nomodifiable') @@ -65,6 +68,25 @@ describe('ui mode_change event', function() ]], mode="normal"} end) + -- oldtest: Test_mouse_shape_after_cancelling_gr() + it('is restored to Normal mode after cancelling "gr"', function() + feed('gr') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + | + ]], mode="replace"} + + feed('<Esc>') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + | + ]], mode="normal"} + end) + it('works in insert mode', function() feed('i') screen:expect{grid=[[ diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index f705678bd5..1356ba3db8 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') 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 poke_eventloop = helpers.poke_eventloop local command = helpers.command local exec = helpers.exec @@ -11,8 +12,8 @@ describe('ui/mouse/input', function() before_each(function() clear() - meths.set_option('mouse', 'a') - meths.set_option('list', true) + meths.set_option_value('mouse', 'a', {}) + meths.set_option_value('list', true, {}) -- NB: this is weird, but mostly irrelevant to the test -- So I didn't bother to change it command('set listchars=eol:$') @@ -32,6 +33,7 @@ describe('ui/mouse/input', function() [5] = {bold = true, reverse = true}, [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [7] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [8] = {foreground = Screen.colors.Brown}, }) command("set mousemodel=extend") feed('itesting<cr>mouse<cr>support and selection<esc>') @@ -64,7 +66,7 @@ describe('ui/mouse/input', function() end) it("in external ui works with unset 'mouse'", function() - meths.set_option('mouse', '') + meths.set_option_value('mouse', '', {}) feed('<LeftMouse><2,1>') screen:expect{grid=[[ testing | @@ -379,7 +381,7 @@ describe('ui/mouse/input', function() end) it('left click in default tabline (position 24) closes tab', function() - meths.set_option('hidden', true) + meths.set_option_value('hidden', true, {}) feed_command('%delete') insert('this is foo') feed_command('silent file foo | tabnew | file bar') @@ -402,7 +404,7 @@ describe('ui/mouse/input', function() end) it('double click in default tabline (position 4) opens new tab', function() - meths.set_option('hidden', true) + meths.set_option_value('hidden', true, {}) feed_command('%delete') insert('this is foo') feed_command('silent file foo | tabnew | file bar') @@ -437,8 +439,8 @@ describe('ui/mouse/input', function() return call('Test', a:000 + [2]) endfunction ]]) - meths.set_option('tabline', '%@Test@test%X-%5@Test2@test2') - meths.set_option('showtabline', 2) + meths.set_option_value('tabline', '%@Test@test%X-%5@Test2@test2', {}) + meths.set_option_value('showtabline', 2, {}) screen:expect([[ {fill:test-test2 }| testing | @@ -786,11 +788,11 @@ describe('ui/mouse/input', function() end) it('ctrl + left click will search for a tag', function() - meths.set_option('tags', './non-existent-tags-file') + meths.set_option_value('tags', './non-existent-tags-file', {}) feed('<C-LeftMouse><0,0>') screen:expect([[ {6:E433: No tags file} | - {6:E426: tag not found: test}| + {6:E426: Tag not found: test}| {6:ing} | {7:Press ENTER or type comma}| {7:nd to continue}^ | @@ -798,6 +800,66 @@ describe('ui/mouse/input', function() feed('<cr>') end) + it('dragging vertical separator', function() + screen:try_resize(45, 5) + command('setlocal nowrap') + local oldwin = meths.get_current_win().id + command('rightbelow vnew') + screen:expect([[ + testing │{0:^$} | + mouse │{0:~ }| + support and selection │{0:~ }| + {4:[No Name] [+] }{5:[No Name] }| + | + ]]) + meths.input_mouse('left', 'press', '', 0, 0, 22) + poke_eventloop() + meths.input_mouse('left', 'drag', '', 0, 1, 12) + screen:expect([[ + testing │{0:^$} | + mouse │{0:~ }| + support and │{0:~ }| + {4:< Name] [+] }{5:[No Name] }| + | + ]]) + meths.input_mouse('left', 'drag', '', 0, 2, 2) + screen:expect([[ + te│{0:^$} | + mo│{0:~ }| + su│{0:~ }| + {4:< }{5:[No Name] }| + | + ]]) + meths.input_mouse('left', 'release', '', 0, 2, 2) + meths.set_option_value('statuscolumn', 'foobar', { win = oldwin }) + screen:expect([[ + {8:fo}│{0:^$} | + {8:fo}│{0:~ }| + {8:fo}│{0:~ }| + {4:< }{5:[No Name] }| + | + ]]) + meths.input_mouse('left', 'press', '', 0, 0, 2) + poke_eventloop() + meths.input_mouse('left', 'drag', '', 0, 1, 12) + screen:expect([[ + {8:foobar}testin│{0:^$} | + {8:foobar}mouse │{0:~ }| + {8:foobar}suppor│{0:~ }| + {4:< Name] [+] }{5:[No Name] }| + | + ]]) + meths.input_mouse('left', 'drag', '', 0, 2, 22) + screen:expect([[ + {8:foobar}testing │{0:^$} | + {8:foobar}mouse │{0:~ }| + {8:foobar}support and sele│{0:~ }| + {4:[No Name] [+] }{5:[No Name] }| + | + ]]) + meths.input_mouse('left', 'release', '', 0, 2, 22) + end) + local function wheel(use_api) feed('ggdG') insert([[ @@ -1011,37 +1073,7 @@ describe('ui/mouse/input', function() ]]) end) - describe('on concealed text', function() - -- Helpful for reading the test expectations: - -- :match Error /\^/ - - before_each(function() - screen:try_resize(25, 7) - screen:set_default_attr_ids({ - [0] = {bold=true, foreground=Screen.colors.Blue}, - c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, - sm = {bold = true}, - }) - feed('ggdG') - - feed_command('set concealcursor=ni') - feed_command('set nowrap') - feed_command('set shiftwidth=2 tabstop=4 list') - feed_command('setl listchars=tab:>-') - feed_command('syntax match NonText "\\*" conceal') - feed_command('syntax match NonText "cats" conceal cchar=X') - feed_command('syntax match NonText "x" conceal cchar=>') - - -- First column is there to retain the tabs. - insert([[ - |Section *t1* - | *t2* *t3* *t4* - |x 私は猫が大好き *cats* ✨🐈✨ - ]]) - - feed('gg<c-v>Gxgg') - end) - + local function test_mouse_click_conceal() it('(level 1) click on non-wrapped lines', function() feed_command('let &conceallevel=1', 'echo') @@ -1433,7 +1465,6 @@ describe('ui/mouse/input', function() ]]) end) -- level 2 - wrapped - it('(level 3) click on non-wrapped lines', function() feed_command('let &conceallevel=3', 'echo') @@ -1471,6 +1502,7 @@ describe('ui/mouse/input', function() ]]) feed('<esc><LeftMouse><20,2>') + feed('zH') -- FIXME: unnecessary horizontal scrolling screen:expect([[ Section{0:>>--->--->---}t1 | {0:>--->--->---} t2 t3 t4 | @@ -1574,12 +1606,80 @@ describe('ui/mouse/input', function() ]]) end) -- level 3 - wrapped + end + + describe('on concealed text', function() + -- Helpful for reading the test expectations: + -- :match Error /\^/ + + before_each(function() + screen:try_resize(25, 7) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, + c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, + sm = { bold = true }, + }) + feed('ggdG') + + command([[setlocal concealcursor=ni nowrap shiftwidth=2 tabstop=4 list listchars=tab:>-]]) + command([[highlight link X0 Normal]]) + command([[highlight link X1 NonText]]) + command([[highlight link X2 NonText]]) + command([[highlight link X3 NonText]]) + + -- First column is there to retain the tabs. + insert([[ + |Section *t1* + | *t2* *t3* *t4* + |x 私は猫が大好き *cats* ✨🐈✨ + ]]) + + feed('gg<c-v>Gxgg') + end) + + describe('(syntax)', function() + before_each(function() + command([[syntax region X0 matchgroup=X1 start=/\*/ end=/\*/ concealends contains=X2]]) + command([[syntax match X2 /cats/ conceal cchar=X contained]]) + command([[syntax match X3 /\n\@<=x/ conceal cchar=>]]) + end) + test_mouse_click_conceal() + end) + + describe('(matchadd())', function() + before_each(function() + funcs.matchadd('Conceal', [[\*]]) + funcs.matchadd('Conceal', [[cats]], 10, -1, { conceal = 'X' }) + funcs.matchadd('Conceal', [[\n\@<=x]], 10, -1, { conceal = '>' }) + end) + test_mouse_click_conceal() + end) + + describe('(extmarks)', function() + before_each(function() + local ns = meths.create_namespace('conceal') + meths.buf_set_extmark(0, ns, 0, 11, { end_col = 12, conceal = '' }) + meths.buf_set_extmark(0, ns, 0, 14, { end_col = 15, conceal = '' }) + meths.buf_set_extmark(0, ns, 1, 5, { end_col = 6, conceal = '' }) + meths.buf_set_extmark(0, ns, 1, 8, { end_col = 9, conceal = '' }) + meths.buf_set_extmark(0, ns, 1, 10, { end_col = 11, conceal = '' }) + meths.buf_set_extmark(0, ns, 1, 13, { end_col = 14, conceal = '' }) + meths.buf_set_extmark(0, ns, 1, 15, { end_col = 16, conceal = '' }) + meths.buf_set_extmark(0, ns, 1, 18, { end_col = 19, conceal = '' }) + meths.buf_set_extmark(0, ns, 2, 24, { end_col = 25, conceal = '' }) + meths.buf_set_extmark(0, ns, 2, 29, { end_col = 30, conceal = '' }) + meths.buf_set_extmark(0, ns, 2, 25, { end_col = 29, conceal = 'X' }) + meths.buf_set_extmark(0, ns, 2, 0, { end_col = 1, conceal = '>' }) + end) + test_mouse_click_conceal() + end) + end) - it('getmousepos works correctly', function() - local winwidth = meths.get_option('winwidth') + it('getmousepos() works correctly', function() + local winwidth = meths.get_option_value('winwidth', {}) -- Set winwidth=1 so that window sizes don't change. - meths.set_option('winwidth', 1) + meths.set_option_value('winwidth', 1, {}) command('tabedit') local tabpage = meths.get_current_tabpage() insert('hello') @@ -1597,8 +1697,8 @@ describe('ui/mouse/input', function() } local float = meths.open_win(meths.get_current_buf(), false, opts) command('redraw') - local lines = meths.get_option('lines') - local columns = meths.get_option('columns') + local lines = meths.get_option_value('lines', {}) + local columns = meths.get_option_value('columns', {}) -- Test that screenrow and screencol are set properly for all positions. for row = 0, lines - 1 do @@ -1617,6 +1717,7 @@ describe('ui/mouse/input', function() eq(0, mousepos.wincol) eq(0, mousepos.line) eq(0, mousepos.column) + eq(0, mousepos.coladd) end end end @@ -1636,15 +1737,18 @@ describe('ui/mouse/input', function() eq(win_col + 1, mousepos.wincol) local line = 0 local column = 0 + local coladd = 0 if win_row > 0 and win_row < opts.height + 1 and win_col > 0 and win_col < opts.width + 1 then -- Because of border, win_row and win_col don't need to be -- incremented by 1. line = math.min(win_row, funcs.line('$')) column = math.min(win_col, #funcs.getline(line) + 1) + coladd = win_col - column end eq(line, mousepos.line) eq(column, mousepos.column) + eq(coladd, mousepos.coladd) end end @@ -1664,14 +1768,16 @@ describe('ui/mouse/input', function() eq(win_col + 1, mousepos.wincol) local line = math.min(win_row + 1, funcs.line('$')) local column = math.min(win_col + 1, #funcs.getline(line) + 1) + local coladd = win_col + 1 - column eq(line, mousepos.line) eq(column, mousepos.column) + eq(coladd, mousepos.coladd) end end -- Test that mouse position values are properly set for ordinary windows. -- Set the float to be unfocusable instead of closing, to additionally test - -- that getmousepos does not consider unfocusable floats. (see discussion + -- that getmousepos() does not consider unfocusable floats. (see discussion -- in PR #14937 for details). opts.focusable = false meths.win_set_config(float, opts) @@ -1688,15 +1794,17 @@ describe('ui/mouse/input', function() eq(win_col + 1, mousepos.wincol) local line = math.min(win_row + 1, funcs.line('$')) local column = math.min(win_col + 1, #funcs.getline(line) + 1) + local coladd = win_col + 1 - column eq(line, mousepos.line) eq(column, mousepos.column) + eq(coladd, mousepos.coladd) end end end -- Restore state and release mouse. command('tabclose!') - meths.set_option('winwidth', winwidth) + meths.set_option_value('winwidth', winwidth, {}) meths.input_mouse('left', 'release', '', 0, 0, 0) end) @@ -1840,16 +1948,6 @@ describe('ui/mouse/input', function() eq({2, 9}, meths.win_get_cursor(0)) eq('', funcs.getreg('"')) - -- Try clicking on the status line - funcs.setreg('"', '') - meths.win_set_cursor(0, {1, 9}) - feed('vee') - meths.input_mouse('right', 'press', '', 0, 5, 1) - meths.input_mouse('right', 'release', '', 0, 5, 1) - feed('<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}) @@ -1859,5 +1957,28 @@ describe('ui/mouse/input', function() feed('<Down><CR>') eq(2, funcs.winnr()) eq('', funcs.getreg('"')) + + -- Test for right click in visual mode inside the selection with vertical splits + command('wincmd t') + command('rightbelow vsplit') + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 9}) + feed('vee') + meths.input_mouse('right', 'press', '', 0, 0, 52) + meths.input_mouse('right', 'release', '', 0, 0, 52) + feed('<Down><CR>') + eq({1, 9}, meths.win_get_cursor(0)) + eq('ran away', funcs.getreg('"')) + + -- Test for right click inside visual selection at bottom of window with winbar + command('setlocal winbar=WINBAR') + feed('2yyP') + funcs.setreg('"', '') + feed('G$vbb') + meths.input_mouse('right', 'press', '', 0, 4, 61) + meths.input_mouse('right', 'release', '', 0, 4, 61) + feed('<Down><CR>') + eq({4, 20}, meths.win_get_cursor(0)) + eq('the moon', funcs.getreg('"')) end) end) diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua index d4e237bcb4..d72bf27d6b 100644 --- a/test/functional/ui/multibyte_spec.lua +++ b/test/functional/ui/multibyte_spec.lua @@ -17,10 +17,11 @@ describe("multibyte rendering", function() screen = Screen.new(60, 6) screen:attach({rgb=true}) screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, + [1] = {bold = true, foreground = Screen.colors.Blue}, [2] = {background = Screen.colors.WebGray}, [3] = {background = Screen.colors.LightMagenta}, [4] = {bold = true}, + [5] = {foreground = Screen.colors.Blue}, }) end) @@ -119,6 +120,19 @@ describe("multibyte rendering", function() ]]) end) + it('0xffff is shown as 4 hex digits', function() + command([[call setline(1, "\uFFFF!!!")]]) + feed('$') + screen:expect{grid=[[ + {5:<ffff>}!!^! | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) + it('works with a lot of unicode (zalgo) text', function() screen:try_resize(65, 10) meths.buf_set_lines(0,0,-1,true, split(dedent [[ @@ -146,6 +160,103 @@ describe("multibyte rendering", function() {1:~ }| | ]]} + + -- nvim will reset the zalgo text^W^W glyph cache if it gets too full. + -- this should be exceedingly rare, but fake it to make sure it works + meths._invalidate_glyph_cache() + screen:expect{grid=[[ + ^L̓̉̑̒̌̚ơ̗̌̒̄̀ŕ̈̈̎̐̕è̇̅̄̄̐m̖̟̟̅̄̚ ̛̓̑̆̇̍i̗̟̞̜̅̐p̗̞̜̉̆̕s̟̜̘̍̑̏ū̟̞̎̃̉ḿ̘̙́́̐ ̖̍̌̇̉̚d̞̄̃̒̉̎ò́̌̌̂̐l̞̀̄̆̌̚ȯ̖̞̋̀̐r̓̇̌̃̃̚ ̗̘̀̏̍́s̜̀̎̎̑̕i̟̗̐̄̄̚t̝̎̆̓̐̒ ̘̇̔̓̊̚ȃ̛̟̗̏̅m̜̟̙̞̈̓é̘̞̟̔̆t̝̂̂̈̑̔,̜̜̖̅̄̍ ̛̗̊̓̆̚c̟̍̆̍̈̔ȯ̖̖̝̑̀n̜̟̎̊̃̚s̟̏̇̎̒̚e̙̐̈̓̌̚c̙̍̈̏̅̕ť̇̄̇̆̓e̛̓̌̈̓̈t̟̍̀̉̆̅u̝̞̎̂̄̚r̘̀̅̈̅̐ ̝̞̓́̇̉ã̏̀̆̅̕d̛̆̐̉̆̋ȉ̞̟̍̃̚p̛̜̊̍̂̓ȋ̏̅̃̋̚ṥ̛̏̃̕č̛̞̝̀̂í̗̘̌́̎n̔̎́̒̂̕ǧ̗̜̋̇̂ ̛̜̔̄̎̃ê̛̔̆̇̕l̘̝̏̐̊̏ĩ̛̍̏̏̄t̟̐́̀̐̎,̙̘̍̆̉̐ ̋̂̏̄̌̅s̙̓̌̈́̇e̛̗̋̒̎̏d̜̗̊̍̊̚ | + ď̘̋̌̌̕ǒ̝̗̔̇̕ ̙̍́̄̄̉è̛̛̞̌̌i̜̖̐̈̆̚ȕ̇̈̓̃̓ŝ̛̞̙̉̋m̜̐̂̄̋̂ȯ̈̎̎̅̕d̜̙̓̔̋̑ ̞̗̄̂̂̚t̝̊́̃́̄e̛̘̜̞̓̑m̊̅̏̉̌̕p̛̈̂̇̀̐ỏ̙̘̈̉̔r̘̞̋̍̃̚ ̝̄̀̇̅̇ỉ̛̖̍̓̈n̛̛̝̎̕̕c̛̛̊̅́̐ĭ̗̓̀̍̐d̞̜̋̐̅̚i̟̙̇̄̊̄d̞̊̂̀̇̚ủ̝̉̑̃̕n̜̏̇̄̐̋ť̗̜̞̋̉ ̝̒̓̌̓̚ȕ̖̙̀̚̕t̖̘̎̉̂̌ ̛̝̄̍̌̂l̛̟̝̃̑̋á̛̝̝̔̅b̝̙̜̗̅̒ơ̖̌̒̄̆r̒̇̓̎̈̄e̛̛̖̅̏̇ ̖̗̜̝̃́e̛̛̘̅̔̌ẗ̛̙̗̐̕ ̖̟̇̋̌̈d̞̙̀̉̑̕ŏ̝̂́̐̑l̞̟̗̓̓̀ơ̘̎̃̄̂r̗̗̖̔̆̍ẻ̖̝̞̋̅ ̜̌̇̍̈̊m̈̉̇̄̒̀a̜̞̘̔̅̆g̗̖̈̃̈̉n̙̖̄̈̉̄â̛̝̜̄̃ ̛́̎̕̕̚ā̊́́̆̌l̟̙̞̃̒́i̖̇̎̃̀̋q̟̇̒̆́̊ủ́̌̇̑̚ã̛̘̉̐̚.̛́̏̐̍̊ | + U̝̙̎̈̐̆t̜̍̌̀̔̏ ̞̉̍̇̈̃e̟̟̊̄̕̕n̝̜̒̓̆̕i̖̒̌̅̇̚m̞̊̃̔̊̂ ̛̜̊̎̄̂a̘̜̋̒̚̚d̟̊̎̇̂̍ ̜̖̏̑̉̕m̜̒̎̅̄̚i̝̖̓̂̍̕n̙̉̒̑̀̔ỉ̖̝̌̒́m̛̖̘̅̆̎ ̖̉̎̒̌̕v̖̞̀̔́̎e̖̙̗̒̎̉n̛̗̝̎̀̂ȉ̞̗̒̕̚ȧ̟̜̝̅̚m̆̉̐̐̇̈,̏̐̎́̍́ ̜̞̙̘̏̆q̙̖̙̅̓̂ủ̇́̀̔̚í̙̟̟̏̐s̖̝̍̏̂̇ ̛̘̋̈̕̕ń̛̞̜̜̎o̗̜̔̔̈̆s̞̘̘̄̒̋t̛̅̋́̔̈ȓ̓̒́̇̅ủ̜̄̃̒̍d̙̝̘̊̏̚ ̛̟̞̄́̔e̛̗̝̍̃̀x̞̖̃̄̂̅e̖̅̇̐̔̃r̗̞̖̔̎̚c̘̜̖̆̊̏ï̙̝̙̂̕t̖̏́̓̋̂ă̖̄̆̑̒t̜̟̍̉̑̏i̛̞̞̘̒̑ǒ̜̆̅̃̉ṅ̖̜̒̎̚ | + u̗̞̓̔̈̏ĺ̟̝́̎̚l̛̜̅̌̎̆a̒̑̆̔̇̃m̜̗̈̊̎̚ċ̘̋̇̂̚ơ̟̖̊́̕ ̖̟̍̉̏̚l̙̔̓̀̅̏ä̞̗̘̙̅ḃ̟̎̄̃̕o̞̎̓̓̓̚r̗̜̊̓̈̒ï̗̜̃̃̅s̀̒̌̂̎̂ ̖̗̗̋̎̐n̝̟̝̘̄̚i̜̒̀̒̐̕s̘̘̄̊̃̀ī̘̜̏̌̕ ̗̖̞̐̈̒ư̙̞̄́̌t̟̘̖̙̊̚ ̌̅̋̆̚̚ä̇̊̇̕̕l̝̞̘̋̔̅i̍̋́̆̑̈q̛̆̐̈̐̚ư̏̆̊́̚î̜̝̑́̊p̗̓̅̑̆̏ ̆́̓̔̋̋e̟̊̋̏̓̚x̗̍̑̊̎̈ ̟̞̆̄̂̍ë̄̎̄̃̅a̛̜̅́̃̈ ̔̋̀̎̐̀c̖̖̍̀̒̂ơ̛̙̖̄̒m̘̔̍̏̆̕ḿ̖̙̝̏̂ȍ̓̋̈̀̕d̆̂̊̅̓̚o̖̔̌̑̚̕ ̙̆́̔̊̒c̖̘̖̀̄̍o̓̄̑̐̓̒ñ̞̒̎̈̚s̞̜̘̈̄̄e̙̊̀̇̌̋q̐̒̓́̔̃ư̗̟̔̔̚å̖̙̞̄̏t̛̙̟̒̇̏.̙̗̓̃̓̎ | + D̜̖̆̏̌̌ư̑̃̌̍̕i̝̊̊̊̊̄s̛̙̒́̌̇ ̛̃̔̄̆̌ă̘̔̅̅̀ú̟̟̟̃̃t̟̂̄̈̈̃e̘̅̌̒̂̆ ̖̟̐̉̉̌î̟̟̙̜̇r̛̙̞̗̄̌ú̗̗̃̌̎r̛̙̘̉̊̕e̒̐̔̃̓̋ ̊̊̍̋̑̉d̛̝̙̉̀̓o̘̜̐̐̓̐l̞̋̌̆̍́o̊̊̐̃̃̚ṙ̛̖̘̃̕ ̞̊̀̍̒̕ȉ́̑̐̇̅ǹ̜̗̜̞̏ ̛̜̐̄̄̚r̜̖̈̇̅̋ĕ̗̉̃̔̚p̟̝̀̓̔̆r̜̈̆̇̃̃e̘̔̔̏̎̓h̗̒̉̑̆̚ė̛̘̘̈̐n̘̂̀̒̕̕d̗̅̂̋̅́ê̗̜̜̜̕r̟̋̄̐̅̂i̛̔̌̒̂̕t̛̗̓̎̀̎ ̙̗̀̉̂̚ȉ̟̗̐̓̚n̙̂̍̏̓̉ ̙̘̊̋̍̕v̜̖̀̎̆̐ő̜̆̉̃̎l̑̋̒̉̔̆ư̙̓̓́̚p̝̘̖̎̏̒t̛̘̝̞̂̓ȁ̘̆̔́̊t̖̝̉̒̐̎e̞̟̋̀̅̄ ̆̌̃̀̑̔v̝̘̝̍̀̇ȅ̝̊̄̓̕l̞̝̑̔̂̋ĭ̝̄̅̆̍t̝̜̉̂̈̇ | + ē̟̊̇̕̚s̖̘̘̒̄̑s̛̘̀̊̆̇e̛̝̘̒̏̚ ̉̅̑̂̐̎c̛̟̙̎̋̓i̜̇̒̏̆̆l̟̄́̆̊̌l̍̊̋̃̆̌ủ̗̙̒̔̚m̛̘̘̖̅̍ ̖̙̈̎̂̕d̞̟̏̋̈̔ơ̟̝̌̃̄l̗̙̝̂̉̒õ̒̃̄̄̚ŕ̗̏̏̊̍ê̞̝̞̋̈ ̜̔̒̎̃̚e̞̟̞̒̃̄ư̖̏̄̑̃ ̛̗̜̄̓̎f̛̖̞̅̓̃ü̞̏̆̋̕g̜̝̞̑̑̆i̛̘̐̐̅̚à̜̖̌̆̎t̙̙̎̉̂̍ ̋̔̈̎̎̉n̞̓́̔̊̕ư̘̅̋̔̚l̗̍̒̄̀̚l̞̗̘̙̓̍â̘̔̒̎̚ ̖̓̋̉̃̆p̛̛̘̋̌̀ä̙̔́̒̕r̟̟̖̋̐̋ì̗̙̎̓̓ȃ̔̋̑̚̕t̄́̎̓̂̋ư̏̈̂̑̃r̖̓̋̊̚̚.̒̆̑̆̊̎ ̘̜̍̐̂̚E̞̅̐̇́̂x̄́̈̌̉̕ć̘̃̉̃̕è̘̂̑̏̑p̝̘̑̂̌̆t̔̐̅̍̌̂ȇ̞̈̐̚̕ű̝̞̜́̚ŕ̗̝̉̆́ | + š̟́̔̏̀ȉ̝̟̝̏̅n̑̆̇̒̆̚t̝̒́̅̋̏ ̗̑̌̋̇̚ơ̙̗̟̆̅c̙̞̙̎̊̎c̘̟̍̔̊̊a̛̒̓̉́̐e̜̘̙̒̅̇ć̝̝̂̇̕ả̓̍̎̂̚t̗̗̗̟̒̃ ̘̒̓̐̇́c̟̞̉̐̓̄ȕ̙̗̅́̏p̛̍̋̈́̅i̖̓̒̍̈̄d̞̃̈̌̆̐a̛̗̝̎̋̉t̞̙̀̊̆̇a̛̙̒̆̉̚t̜̟̘̉̓̚ ̝̘̗̐̇̕n̛̘̑̏̂́ō̑̋̉̏́ň̞̊̆̄̃ ̙̙̙̜̄̏p̒̆̋̋̓̏r̖̖̅̉́̚ơ̜̆̑̈̚i̟̒̀̃̂̌d̛̏̃̍̋̚ë̖̞̙̗̓n̛̘̓̒̅̎t̟̗̙̊̆̚,̘̙̔̊̚̕ ̟̗̘̜̑̔s̜̝̍̀̓̌û̞̙̅̇́n̘̗̝̒̃̎t̗̅̀̅̊̈ ̗̖̅̅̀̄i̛̖̍̅̋̂n̙̝̓̓̎̚ ̞̋̅̋̃̚c̗̒̀̆̌̎ū̞̂̑̌̓ĺ̛̐̍̑́p̝̆̌̎̈̚a̖̙̒̅̈̌ ̝̝̜̂̈̀q̝̖̔̍̒̚ư̔̐̂̎̊ǐ̛̟̖̘̕ | + o̖̜̔̋̅̚f̛̊̀̉́̕f̏̉̀̔̃̃i̘̍̎̐̔̎c̙̅̑̂̐̅ȋ̛̜̀̒̚a̋̍̇̏̀̋ ̖̘̒̅̃̒d̗̘̓̈̇̋é̝́̎̒̄š̙̒̊̉̋e̖̓̐̀̍̕r̗̞̂̅̇̄ù̘̇̐̉̀n̐̑̀̄̍̐t̟̀̂̊̄̚ ̟̝̂̍̏́m̜̗̈̂̏̚ő̞̊̑̇̒l̘̑̏́̔̄l̛̛̇̃̋̊i̓̋̒̃̉̌t̛̗̜̏̀̋ ̙̟̒̂̌̐a̙̝̔̆̏̅n̝̙̙̗̆̅i̍̔́̊̃̕m̖̝̟̒̍̚ ̛̃̃̑̌́ǐ̘̉̔̅̚d̝̗̀̌̏̒ ̖̝̓̑̊̚ȇ̞̟̖̌̕š̙̙̈̔̀t̂̉̒̍̄̄ ̝̗̊̋̌̄l̛̞̜̙̘̔å̝̍̂̍̅b̜̆̇̈̉̌ǒ̜̙̎̃̆r̝̀̄̍́̕ư̋̊́̊̕m̜̗̒̐̕̚.̟̘̀̒̌̚ | + {1:~ }| + | + ]], reset=true} + end) + + it('works with arabic input and arabicshape', function() + command('set arabic') + + command('set noarabicshape') + feed('isghl!<esc>') + screen:expect{grid=[[ + ^!مالس| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + | + ]]} + + command('set arabicshape') + screen:expect{grid=[[ + ^!ﻡﻼﺳ| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + | + ]]} + end) + + it('works with arabic input and arabicshape and norightleft', function() + command('set arabic norightleft') + + command('set noarabicshape') + feed('isghl!<esc>') + screen:expect{grid=[[ + سلام^! | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + command('set arabicshape') + screen:expect{grid=[[ + ﺱﻼﻣ^! | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + end) + + it('works with arabicshape and multiple composing chars', function() + -- this tests an important edge case: arabicshape might increase the byte size of the base + -- character in a way so that the last composing char no longer fits. use "g8" on the text + -- to observe what is happening (the final E1 80 B7 gets deleted with 'arabicshape') + -- If we would increase the schar_t size, say from 32 to 64 bytes, we need to extend the + -- test text with even more zalgo energy to still touch this edge case. + + meths.buf_set_lines(0,0,-1,true, {"سلام့̀́̂̃̄̅̆̇̈̉̊̋̌"}) + command('set noarabicshape') + + screen:expect{grid=[[ + ^سلام့̀́̂̃̄̅̆̇̈̉̊̋̌ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + command('set arabicshape') + screen:expect{grid=[[ + ^ﺱﻼﻣ̀́̂̃̄̅̆̇̈̉̊̋̌ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} end) end) @@ -158,6 +269,7 @@ describe('multibyte rendering: statusline', function() screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {bold = true, reverse = true}, + [3] = {background = Screen.colors.Red, foreground = Screen.colors.Gray100}; }) screen:attach() command('set laststatus=2') @@ -220,4 +332,27 @@ describe('multibyte rendering: statusline', function() | ]]} end) + + it('unprintable chars in filename with default stl', function() + command("file 🧑💻") + -- TODO: this is wrong but avoids a crash + screen:expect{grid=[[ + ^ | + {1:~ }| + {2:🧑�💻 }| + | + ]]} + end) + + it('unprintable chars in filename with custom stl', function() + command('set statusline=xx%#ErrorMsg#%f%##yy') + command("file 🧑💻") + -- TODO: this is also wrong but also avoids a crash + screen:expect{grid=[[ + ^ | + {1:~ }| + {2:xx}{3:🧑<200d>💻}{2:yy }| + | + ]]} + end) end) diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index 71adeb42a4..5b982df2b5 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -37,6 +37,10 @@ describe('ext_multigrid', function() [18] = {bold = true, foreground = Screen.colors.Magenta}, [19] = {foreground = Screen.colors.Brown}, [20] = {background = Screen.colors.LightGrey}, + [21] = {background = Screen.colors.LightMagenta}, + [22] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue}, + [23] = {background = Screen.colors.Grey90}, + [24] = {background = Screen.colors.Grey}, }) end) @@ -884,7 +888,6 @@ describe('ext_multigrid', function() it('gets written till grid width', function() insert(('a'):rep(60).."\n") - screen:expect{grid=[[ ## grid 1 [2:-----------------------------------------------------]| @@ -927,8 +930,95 @@ describe('ext_multigrid', function() ]]} end) + it('"g$" works correctly with double-width characters and no wrapping', function() + command('set nowrap') + insert(('a'):rep(58) .. ('哦'):rep(3)) + feed('0') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa哦| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]} + feed('g$') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^哦| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]} + end) + it('wraps with grid width', function() - insert(('b'):rep(80).."\n") + insert(('b'):rep(160).."\n") screen:expect{grid=[[ ## grid 1 [2:-----------------------------------------------------]| @@ -947,7 +1037,8 @@ describe('ext_multigrid', function() [3:-----------------------------------------------------]| ## grid 2 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb| - bbbbbbbbbbbbbbbbbbbb | + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | ^ | {1:~ }| {1:~ }| @@ -965,6 +1056,47 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| {1:~ }| + ## grid 3 + | + ]]} + feed('2gk') + command('setlocal cursorline cursorlineopt=screenline') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb| + {23:^bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb}| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | @@ -1060,6 +1192,255 @@ describe('ext_multigrid', function() | ]]} end) + + it('anchored float window "bufpos"', function() + insert(('c'):rep(1111)) + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccc^c | + {1:~ }| + ## grid 3 + | + ]]} + local float_buf = meths.create_buf(false, false) + meths.open_win(float_buf, false, { + relative = 'win', + win = curwin(), + bufpos = {0, 1018}, + anchor = 'SE', + width = 5, + height = 5, + }) + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc| + cccccccccccccccccccccccccccccc^c | + {1:~ }| + ## grid 3 + | + ## grid 4 + {21: }| + {22:~ }| + {22:~ }| + {22:~ }| + {22:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "SE", 2, 16, 58, true, 50}; + }} + end) + + it('completion popup position', function() + insert(('\n'):rep(14) .. ('foo bar '):rep(7)) + feed('A<C-X><C-N>') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + | + | + | + | + | + | + | + | + | + | + | + | + | + | + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- Keyword Local completion (^N^P) }{15:match 1 of 2} | + ## grid 4 + {24: foo}| + {21: bar}| + ]], float_pos={ + [4] = {{id = -1}, "NW", 2, 15, 55, false, 100}; + }} + feed('<C-E><Esc>') + + command('setlocal rightleft') + feed('o<C-X><C-N>') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + | + | + | + | + | + | + | + | + | + | + | + | + | + | + rab oof rab oof rab oof rab oof rab oof rab oof rab oof| + ^ oof| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + ## grid 3 + {7:-- Keyword Local completion (^N^P) }{15:match 1 of 2} | + ## grid 4 + {24: oof}| + {21: rab}| + ]], float_pos={ + [4] = {{id = -1}, "NW", 2, 16, 45, false, 100}; + }} + feed('<C-E><Esc>') + + command('set wildoptions+=pum') + feed(':sign un<Tab>') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + | + | + | + | + | + | + | + | + | + | + | + | + | + | + rab oof rab oof rab oof rab oof rab oof rab oof rab oof| + | + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + ## grid 3 + :sign undefine^ | + ## grid 4 + {24: undefine }| + {21: unplace }| + ]], float_pos={ + [4] = {{id = -1}, "SW", 1, 13, 5, false, 250}; + }} + end) end) it('multiline messages scroll over windows', function() @@ -1926,6 +2307,7 @@ describe('ext_multigrid', function() {1:~ }| ]]} + -- XXX: mouse_check_grid() doesn't work properly when clicking on grid 1 meths.input_mouse('left', 'press', '', 1, 6, 20) -- TODO(bfredl): "batching" input_mouse is formally not supported yet. -- Normally it should work fine in async context when nvim is not blocked, @@ -2003,7 +2385,7 @@ describe('ext_multigrid', function() {1:~ }| ]]} - meths.input_mouse('left', 'press', '', 1,8, 26) + meths.input_mouse('left', 'press', '', 1, 8, 26) poke_eventloop() meths.input_mouse('left', 'drag', '', 1, 6, 30) screen:expect{grid=[[ @@ -2044,6 +2426,625 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]]} + + command('aunmenu PopUp | vmenu PopUp.Copy y') + + funcs.setreg('"', '') + meths.input_mouse('left', 'press', '2', 2, 1, 6) + screen:expect{grid=[[ + ## grid 1 + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {12:[No Name] [+] }| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] }{11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be {20:clicke}^d | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- VISUAL --} | + ## grid 4 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo | + {1:~ }| + ## grid 5 + some text | + to be {20:clicked} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + meths.input_mouse('right', 'press', '', 2, 1, 6) + meths.input_mouse('right', 'release', '', 2, 1, 6) + screen:expect{grid=[[ + ## grid 1 + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {12:[No Name] [+] }| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] }{11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be {20:clicke}^d | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- VISUAL --} | + ## grid 4 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo | + {1:~ }| + ## grid 5 + some text | + to be {20:clicked} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 6 + {21: Copy }| + ]], float_pos={ + [6] = {{id = -1}, "NW", 2, 2, 5, false, 250}; + }} + feed('<Down><CR>') + screen:expect{grid=[[ + ## grid 1 + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {12:[No Name] [+] }| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] }{11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be ^clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo | + {1:~ }| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + eq('clicked', funcs.getreg('"')) + + funcs.setreg('"', '') + meths.input_mouse('left', 'press', '2', 4, 0, 64) + screen:expect{grid=[[ + ## grid 1 + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- VISUAL --} | + ## grid 4 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do {20:eiusm}^o | + {1:~ }| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + meths.input_mouse('right', 'press', '', 4, 0, 64) + meths.input_mouse('right', 'release', '', 4, 0, 64) + screen:expect{grid=[[ + ## grid 1 + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- VISUAL --} | + ## grid 4 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do {20:eiusm}^o | + {1:~ }| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 6 + {21: Copy }| + ]], float_pos={ + [6] = {{id = -1}, "NW", 4, 1, 63, false, 250}; + }} + feed('<Down><CR>') + screen:expect{grid=[[ + ## grid 1 + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do ^eiusmo | + {1:~ }| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + eq('eiusmo', funcs.getreg('"')) + + command('wincmd J') + screen:try_resize_grid(4, 7, 10) + screen:expect{grid=[[ + ## grid 1 + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + Lorem i| + psum do| + lor sit| + amet, | + consect| + etur ad| + ipiscin| + g elit,| + sed do| + ^eiusmo| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + + funcs.setreg('"', '') + meths.input_mouse('left', 'press', '2', 4, 9, 1) + screen:expect{grid=[[ + ## grid 1 + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- VISUAL --} | + ## grid 4 + Lorem i| + psum do| + lor sit| + amet, | + consect| + etur ad| + ipiscin| + g elit,| + sed do| + {20:eiusm}^o| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + meths.input_mouse('right', 'press', '', 4, 9, 1) + meths.input_mouse('right', 'release', '', 4, 9, 1) + screen:expect{grid=[[ + ## grid 1 + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- VISUAL --} | + ## grid 4 + Lorem i| + psum do| + lor sit| + amet, | + consect| + etur ad| + ipiscin| + g elit,| + sed do| + {20:eiusm}^o| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 6 + {21: Copy }| + ]], float_pos={ + [6] = {{id = -1}, "SW", 4, 9, 0, false, 250}; + }} + feed('<Down><CR>') + screen:expect{grid=[[ + ## grid 1 + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + Lorem i| + psum do| + lor sit| + amet, | + consect| + etur ad| + ipiscin| + g elit,| + sed do| + ^eiusmo| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + eq('eiusmo', funcs.getreg('"')) + + screen:try_resize_grid(4, 7, 11) + screen:expect{grid=[[ + ## grid 1 + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + Lorem i| + psum do| + lor sit| + amet, | + consect| + etur ad| + ipiscin| + g elit,| + sed do| + ^eiusmo| + {1:~ }| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + + funcs.setreg('"', '') + meths.input_mouse('left', 'press', '2', 4, 9, 1) + screen:expect{grid=[[ + ## grid 1 + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- VISUAL --} | + ## grid 4 + Lorem i| + psum do| + lor sit| + amet, | + consect| + etur ad| + ipiscin| + g elit,| + sed do| + {20:eiusm}^o| + {1:~ }| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + meths.input_mouse('right', 'press', '', 4, 9, 1) + meths.input_mouse('right', 'release', '', 4, 9, 1) + screen:expect{grid=[[ + ## grid 1 + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {7:-- VISUAL --} | + ## grid 4 + Lorem i| + psum do| + lor sit| + amet, | + consect| + etur ad| + ipiscin| + g elit,| + sed do| + {20:eiusm}^o| + {1:~ }| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 6 + {21: Copy }| + ]], float_pos={ + [6] = {{id = -1}, "NW", 4, 10, 0, false, 250}; + }} + feed('<Down><CR>') + screen:expect{grid=[[ + ## grid 1 + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + [5:------------------------------]│[2:----------------------]| + {12:[No Name] [+] [No Name] [+] }| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + Lorem i| + psum do| + lor sit| + amet, | + consect| + etur ad| + ipiscin| + g elit,| + sed do| + ^eiusmo| + {1:~ }| + ## grid 5 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + eq('eiusmo', funcs.getreg('"')) end) it('supports mouse drag with mouse=a', function() @@ -2127,7 +3128,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1} + [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0} }} insert([[ Lorem ipsum dolor sit amet, consectetur @@ -2162,7 +3163,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11}, + [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11, sum_scroll_delta = 5}, }} @@ -2187,7 +3188,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 2, botline = 9, curline = 7, curcol = 0, linecount = 11}, + [2] = {win = {id = 1000}, topline = 2, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 2}, }} command("split") @@ -2211,8 +3212,8 @@ describe('ext_multigrid', function() reprehenderit in voluptate velit esse cillum | ^dolore eu fugiat nulla pariatur. Excepteur sint | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11}, - [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 7, curcol = 0, linecount = 11}, + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 6}, + [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 5}, }} feed("b") @@ -2236,8 +3237,8 @@ describe('ext_multigrid', function() reprehenderit in voluptate velit esse ^cillum | dolore eu fugiat nulla pariatur. Excepteur sint | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11}, - [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 6, curcol = 38, linecount = 11}, + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 6}, + [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 6, curcol = 38, linecount = 11, sum_scroll_delta = 5}, }} feed("2k") @@ -2261,8 +3262,8 @@ describe('ext_multigrid', function() ea commodo consequat. Duis aute irure dolor in | reprehenderit in voluptate velit esse cillum | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11}, - [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11}, + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 6}, + [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11, sum_scroll_delta = 4}, }} -- handles non-current window @@ -2287,8 +3288,561 @@ describe('ext_multigrid', function() ea commodo consequat. Duis aute irure dolor in | reprehenderit in voluptate velit esse cillum | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11}, - [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11}, + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}, + [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11, sum_scroll_delta = 4}, + }} + + -- sum_scroll_delta works with folds + feed('zfj') + screen:expect{grid=[[ + ## grid 1 + [4:------------------------------------------------]| + [4:------------------------------------------------]| + [4:------------------------------------------------]| + {11:[No Name] [+] }| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + ## grid 3 + | + ## grid 4 + {13:^+-- 2 lines: exercitation ullamco laboris nisi }| + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}, + [4] = {win = {id = 1001}, topline = 4, botline = 9, curline = 4, curcol = 38, linecount = 11, sum_scroll_delta = 4}, + }} + + feed('<c-e>') + screen:expect{grid=[[ + ## grid 1 + [4:------------------------------------------------]| + [4:------------------------------------------------]| + [4:------------------------------------------------]| + {11:[No Name] [+] }| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + ## grid 3 + | + ## grid 4 + ^reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}, + [4] = {win = {id = 1001}, topline = 6, botline = 10, curline = 6, curcol = 0, linecount = 11, sum_scroll_delta = 5}, + }} + + command('close | 21vsplit | setlocal number smoothscroll') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {19: 1 }Lorem ipsu^m dolor| + {19: } sit amet, consec| + {19: }tetur | + {19: 2 }adipisicing elit,| + {19: } sed do eiusmod t| + {19: }empor | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + }} + + feed('5<C-E>') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {1:<<<}{19: }empo^r | + {19: 3 }incididunt ut lab| + {19: }ore et dolore mag| + {19: }na aliqua. | + {19: 4 }Ut enim ad minim | + {19: }veniam, quis n{1:@@@}| + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 1, botline = 4, curline = 1, curcol = 38, linecount = 11, sum_scroll_delta = 5}; + }} + + feed('<C-Y>') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {1:<<<}{19: } sed do eiusmod t| + {19: }empo^r | + {19: 3 }incididunt ut lab| + {19: }ore et dolore mag| + {19: }na aliqua. | + {19: 4 }Ut enim ad min{1:@@@}| + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 1, botline = 4, curline = 1, curcol = 38, linecount = 11, sum_scroll_delta = 4}; + }} + + command('set cpoptions+=n') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {1:<<<}d do eiusmod tempo| + ^r | + {19: 3 }incididunt ut lab| + ore et dolore magna a| + liqua. | + {19: 4 }Ut enim ad min{1:@@@}| + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 1, botline = 4, curline = 1, curcol = 38, linecount = 11, sum_scroll_delta = 4}; + }} + + feed('4<C-E>') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {1:<<<}ua^. | + {19: 4 }Ut enim ad minim | + veniam, quis nostrud | + {19: 5 }exercitation ulla| + mco laboris nisi ut a| + liquip ex | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 2, botline = 6, curline = 2, curcol = 43, linecount = 11, sum_scroll_delta = 8}; + }} + + feed('2<C-Y>') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {19: 3 }incididunt ut lab| + ore et dolore magna a| + liqua^. | + {19: 4 }Ut enim ad minim | + veniam, quis nostrud | + {19: 5 }exercitation u{1:@@@}| + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 2, botline = 5, curline = 2, curcol = 43, linecount = 11, sum_scroll_delta = 6}; + }} + + command('setlocal numberwidth=12') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {19: 3 }incididun| + t ut labore et dolore| + magna aliqua^. | + {19: 4 }Ut enim a| + d minim veniam, quis | + nostrud | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 2, botline = 5, curline = 2, curcol = 43, linecount = 11, sum_scroll_delta = 6}; + }} + + feed('2<C-E>') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {1:<<<}gna aliqua^. | + {19: 4 }Ut enim a| + d minim veniam, quis | + nostrud | + {19: 5 }exercitat| + ion ullamco labori{1:@@@}| + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 2, botline = 5, curline = 2, curcol = 43, linecount = 11, sum_scroll_delta = 8}; + }} + + feed('<C-E>') + screen:expect{grid=[[ + ## grid 1 + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + [5:---------------------]│[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet| + , consectetur | + adipisicing elit, sed do e| + iusmod tempor | + incididunt ut labore et do| + lore magna aliqua. | + ## grid 3 + | + ## grid 5 + {19: 4 }Ut enim a| + d minim veniam, quis | + nostru^d | + {19: 5 }exercitat| + ion ullamco laboris n| + isi ut aliquip ex | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 4, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 3, botline = 6, curline = 3, curcol = 36, linecount = 11, sum_scroll_delta = 9}; + }} + end) + + it('scroll_delta is approximated reasonably when scrolling many lines #24234', function() + command('setlocal number nowrap') + command('edit test/functional/fixtures/bigfile.txt') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:test/functional/fixtures/bigfile.txt }| + [3:-----------------------------------------------------]| + ## grid 2 + {19: 1 }^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; | + {19: 2 }0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;| + {19: 3 }0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + {19: 4 }0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + {19: 5 }0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSIO| + {19: 6 }0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | + {19: 7 }0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | + {19: 8 }0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | + {19: 9 }0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;; | + {19: 10 }0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATIO| + {19: 11 }000A;<control>;Cc;0;B;;;;;N;LINE FEED (LF);;;; | + {19: 12 }000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 13, curline = 0, curcol = 0, linecount = 30592, sum_scroll_delta = 0}; + }} + feed('G') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:test/functional/fixtures/bigfile.txt }| + [3:-----------------------------------------------------]| + ## grid 2 + {19:30581 }E01E8;VARIATION SELECTOR-249;Mn;0;NSM;;;;;N;;;;| + {19:30582 }E01E9;VARIATION SELECTOR-250;Mn;0;NSM;;;;;N;;;;| + {19:30583 }E01EA;VARIATION SELECTOR-251;Mn;0;NSM;;;;;N;;;;| + {19:30584 }E01EB;VARIATION SELECTOR-252;Mn;0;NSM;;;;;N;;;;| + {19:30585 }E01EC;VARIATION SELECTOR-253;Mn;0;NSM;;;;;N;;;;| + {19:30586 }E01ED;VARIATION SELECTOR-254;Mn;0;NSM;;;;;N;;;;| + {19:30587 }E01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;| + {19:30588 }E01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;| + {19:30589 }F0000;<Plane 15 Private Use, First>;Co;0;L;;;;;| + {19:30590 }FFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N| + {19:30591 }100000;<Plane 16 Private Use, First>;Co;0;L;;;;| + {19:30592 }^10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 30580, botline = 30592, curline = 30591, curcol = 0, linecount = 30592, sum_scroll_delta = 30580}; + }} + feed('gg') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:test/functional/fixtures/bigfile.txt }| + [3:-----------------------------------------------------]| + ## grid 2 + {19: 1 }^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; | + {19: 2 }0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;| + {19: 3 }0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + {19: 4 }0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + {19: 5 }0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSIO| + {19: 6 }0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | + {19: 7 }0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | + {19: 8 }0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | + {19: 9 }0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;; | + {19: 10 }0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATIO| + {19: 11 }000A;<control>;Cc;0;B;;;;;N;LINE FEED (LF);;;; | + {19: 12 }000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 13, curline = 0, curcol = 0, linecount = 30592, sum_scroll_delta = 0}; + }} + command('setlocal wrap') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:test/functional/fixtures/bigfile.txt }| + [3:-----------------------------------------------------]| + ## grid 2 + {19: 1 }^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; | + {19: 2 }0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;| + {19: };; | + {19: 3 }0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + {19: 4 }0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + {19: 5 }0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSIO| + {19: }N;;;; | + {19: 6 }0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | + {19: 7 }0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | + {19: 8 }0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | + {19: 9 }0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;; | + {19: 10 }0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULA{1:@@@}| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 10, curline = 0, curcol = 0, linecount = 30592, sum_scroll_delta = 0}; + }} + feed('G') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:test/functional/fixtures/bigfile.txt }| + [3:-----------------------------------------------------]| + ## grid 2 + {19:30587 }E01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;| + {19: }; | + {19:30588 }E01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;| + {19: }; | + {19:30589 }F0000;<Plane 15 Private Use, First>;Co;0;L;;;;;| + {19: }N;;;;; | + {19:30590 }FFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N| + {19: };;;;; | + {19:30591 }100000;<Plane 16 Private Use, First>;Co;0;L;;;;| + {19: };N;;;;; | + {19:30592 }^10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;| + {19: }N;;;;; | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 30586, botline = 30592, curline = 30591, curcol = 0, linecount = 30592, sum_scroll_delta = 30588}; + }} + feed('gg') + screen:expect{grid=[[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:test/functional/fixtures/bigfile.txt }| + [3:-----------------------------------------------------]| + ## grid 2 + {19: 1 }^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; | + {19: 2 }0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;| + {19: };; | + {19: 3 }0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + {19: 4 }0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + {19: 5 }0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSIO| + {19: }N;;;; | + {19: 6 }0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | + {19: 7 }0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | + {19: 8 }0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | + {19: 9 }0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;; | + {19: 10 }0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULA{1:@@@}| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 10, curline = 0, curcol = 0, linecount = 30592, sum_scroll_delta = 0}; }} end) @@ -2314,7 +3868,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1} + [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0} }} insert([[ Lorem ipsum dolor sit amet, consectetur @@ -2349,7 +3903,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11}, + [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11, sum_scroll_delta = 5}, }} meths.input_mouse('left', 'press', '', 1,5, 1) @@ -2376,7 +3930,7 @@ describe('ext_multigrid', function() ## grid 3 {7:-- VISUAL --} | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 6, botline = 12, curline = 10, curcol = 1, linecount = 11}, + [2] = {win = {id = 1000}, topline = 6, botline = 12, curline = 10, curcol = 1, linecount = 11, sum_scroll_delta = 6}, }} end) @@ -2414,8 +3968,8 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} -- XXX: hack to get notifications. Could use next_msg() also. @@ -2459,8 +4013,8 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} eq({}, win_pos) @@ -2497,14 +4051,14 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} eq({}, win_pos) end) it('with winbar dragging statusline with mouse works correctly', function() - meths.set_option('winbar', 'Set Up The Bars') + meths.set_option_value('winbar', 'Set Up The Bars', {}) command('split') screen:expect([[ ## grid 1 @@ -2644,7 +4198,7 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]]) - eq(3, meths.get_option('cmdheight')) + eq(3, meths.get_option_value('cmdheight', {})) meths.input_mouse('left', 'drag', '', 1, 12, 10) screen:expect([[ @@ -2679,6 +4233,6 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]]) - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) end) end) diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index 9d20229ce1..2c649709c6 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -19,9 +19,11 @@ describe('UI receives option updates', function() linespace=0, pumblend=0, mousefocus=false, + mousehide=true, mousemoveevent=false, showtabline=1, termguicolors=false, + termsync=true, ttimeout=true, ttimeoutlen=50, verbose=0, @@ -68,15 +70,18 @@ describe('UI receives option updates', function() eq({'mouse_on'}, evs) end) command("set mouse=") + screen:expect(function() + eq({'mouse_on', 'mouse_off'}, evs) + end) command("set mouse&") screen:expect(function() - eq({'mouse_on','mouse_off', 'mouse_on'}, evs) + eq({'mouse_on', 'mouse_off', 'mouse_on'}, evs) end) screen:detach() - eq({'mouse_on','mouse_off', 'mouse_on'}, evs) + eq({'mouse_on', 'mouse_off', 'mouse_on'}, evs) screen:attach() screen:expect(function() - eq({'mouse_on','mouse_off','mouse_on', 'mouse_on'}, evs) + eq({'mouse_on', 'mouse_off', 'mouse_on', 'mouse_on'}, evs) end) end) @@ -133,6 +138,12 @@ describe('UI receives option updates', function() eq(expected, screen.options) end) + command("set nomousehide") + expected.mousehide = false + screen:expect(function() + eq(expected, screen.options) + end) + command("set mousemoveevent") expected.mousemoveevent = true screen:expect(function() @@ -200,22 +211,6 @@ describe('UI can set terminal option', function() screen = Screen.new(20,5) end) - it('term_background', function() - eq('dark', eval '&background') - - screen:attach {term_background='light'} - eq('light', eval '&background') - end) - - it("term_background but not if 'background' already set by user", function() - eq('dark', eval '&background') - command 'set background=dark' - - screen:attach {term_background='light'} - - eq('dark', eval '&background') - end) - it('term_name', function() eq('nvim', eval '&term') diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 223844405e..7b93b74eac 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -15,6 +15,8 @@ local set_shell_powershell = helpers.set_shell_powershell local skip = helpers.skip local is_os = helpers.is_os +clear() -- for has_powershell() + describe("shell command :!", function() local screen before_each(function() @@ -54,6 +56,7 @@ describe("shell command :!", function() it("throttles shell-command output greater than ~10KB", function() skip(is_os('openbsd'), 'FIXME #10804') + skip(is_os('win')) child_session.feed_data((":!%s REP 30001 foo\n"):format(testprg('shell-test'))) -- If we observe any line starting with a dot, then throttling occurred. @@ -222,8 +225,8 @@ describe("shell command :!", function() å | ref: å̲ | 1: å̲ | - 2: å ̲ | - 3: å ̲ | + 2: å ̲ | + 3: å ̲ | | {3:Press ENTER or type command to continue}^ | ]]) diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index c681453294..a6cd216d84 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -5,6 +5,7 @@ local clear, feed = helpers.clear, helpers.feed local source = helpers.source local insert = helpers.insert local meths = helpers.meths +local async_meths = helpers.async_meths local command = helpers.command local funcs = helpers.funcs local eq = helpers.eq @@ -1023,1870 +1024,11 @@ describe('ui/ext_popupmenu', function() end) end) +describe("builtin popupmenu 'pumblend'", function() + before_each(clear) -describe('builtin popupmenu', function() - local screen - before_each(function() - clear() - screen = Screen.new(32, 20) - screen:attach() - screen:set_default_attr_ids({ - -- popup selected item / scrollbar track - ['s'] = {background = Screen.colors.WebGray}, - -- popup non-selected item - ['n'] = {background = Screen.colors.LightMagenta}, - -- popup scrollbar knob - ['c'] = {background = Screen.colors.Grey0}, - [1] = {bold = true, foreground = Screen.colors.Blue}, - [2] = {bold = true}, - [3] = {reverse = true}, - [4] = {bold = true, reverse = true}, - [5] = {bold = true, foreground = Screen.colors.SeaGreen}, - [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [7] = {background = Screen.colors.Yellow}, -- Search - [8] = {foreground = Screen.colors.Red}, - }) - end) - - it('with preview-window above', function() - feed(':ped<CR><c-w>4+') - feed('iaa bb cc dd ee ff gg hh ii jj<cr>') - feed('<c-x><c-n>') - screen:expect([[ - aa bb cc dd ee ff gg hh ii jj | - aa | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {3:[No Name] [Preview][+] }| - aa bb cc dd ee ff gg hh ii jj | - aa^ | - {s:aa }{c: }{1: }| - {n:bb }{c: }{1: }| - {n:cc }{c: }{1: }| - {n:dd }{c: }{1: }| - {n:ee }{c: }{1: }| - {n:ff }{c: }{1: }| - {n:gg }{s: }{1: }| - {n:hh }{s: }{4: }| - {2:-- }{5:match 1 of 10} | - ]]) - end) - - it('with preview-window below', function() - feed(':ped<CR><c-w>4+<c-w>r') - feed('iaa bb cc dd ee ff gg hh ii jj<cr>') - feed('<c-x><c-n>') - screen:expect([[ - aa bb cc dd ee ff gg hh ii jj | - aa^ | - {s:aa }{c: }{1: }| - {n:bb }{c: }{1: }| - {n:cc }{c: }{1: }| - {n:dd }{c: }{1: }| - {n:ee }{c: }{1: }| - {n:ff }{c: }{1: }| - {n:gg }{s: }{1: }| - {n:hh }{s: }{4: }| - aa bb cc dd ee ff gg hh ii jj | - aa | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {3:[No Name] [Preview][+] }| - {2:-- }{5:match 1 of 10} | - ]]) - end) - - it('with preview-window above and tall and inverted', function() - feed(':ped<CR><c-w>8+') - feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>') - feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>') - feed('kk<cr>ll<cr>mm<cr>nn<cr>oo<cr>') - feed('<c-x><c-n>') - screen:expect([[ - aa | - bb | - cc | - dd | - {s:aa }{c: }{3:ew][+] }| - {n:bb }{c: } | - {n:cc }{c: } | - {n:dd }{c: } | - {n:ee }{c: } | - {n:ff }{c: } | - {n:gg }{c: } | - {n:hh }{c: } | - {n:ii }{c: } | - {n:jj }{c: } | - {n:kk }{c: } | - {n:ll }{s: } | - {n:mm }{s: } | - aa^ | - {4:[No Name] [+] }| - {2:-- }{5:match 1 of 15} | - ]]) - end) - - it('with preview-window above and short and inverted', function() - feed(':ped<CR><c-w>4+') - feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>') - feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>') - feed('<c-x><c-n>') - screen:expect([[ - aa | - bb | - cc | - dd | - ee | - ff | - gg | - hh | - {s:aa }{c: }{3:ew][+] }| - {n:bb }{c: } | - {n:cc }{c: } | - {n:dd }{c: } | - {n:ee }{c: } | - {n:ff }{c: } | - {n:gg }{c: } | - {n:hh }{c: } | - {n:ii }{s: } | - aa^ | - {4:[No Name] [+] }| - {2:-- }{5:match 1 of 10} | - ]]) - end) - - it('with preview-window below and inverted', function() - feed(':ped<CR><c-w>4+<c-w>r') - feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>') - feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>') - feed('<c-x><c-n>') - screen:expect([[ - {s:aa }{c: } | - {n:bb }{c: } | - {n:cc }{c: } | - {n:dd }{c: } | - {n:ee }{c: } | - {n:ff }{c: } | - {n:gg }{s: } | - {n:hh }{s: } | - aa^ | - {4:[No Name] [+] }| - aa | - bb | - cc | - dd | - ee | - ff | - gg | - hh | - {3:[No Name] [Preview][+] }| - {2:-- }{5:match 1 of 10} | - ]]) - end) - - -- oldtest: Test_pum_with_preview_win() - it('preview window opened during completion', function() - exec([[ - funct Omni_test(findstart, base) - if a:findstart - return col(".") - 1 - endif - return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}] - endfunc - set omnifunc=Omni_test - set completeopt+=longest - ]]) - feed('Gi<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>') - screen:expect([[ - aaa aab aac │aaa aab aac| - ^ │ | - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {4:[No Name] [+] }{3:<Name] [+] }| - :vsplit | - ]]) - - feed('ibbb a<c-x><c-n>') - screen:expect([[ - aaa aab aac │aaa aab aac| - bbb aaa^ │bbb aaa | - {1:~ }{s: aaa }{1: }│{1:~ }| - {1:~ }{n: aab }{1: }│{1:~ }| - {1:~ }{n: aac }{1: }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {4:[No Name] [+] }{3:<Name] [+] }| - {2:-- }{5:match 1 of 3} | - ]]) - - feed('<esc><c-w><c-w>oc a<c-x><c-n>') - screen:expect([[ - aaa aab aac│aaa aab aac | - bbb aaa │bbb aaa | - c aaa │c aaa^ | - {1:~ }│{1:~}{s: aaa }{1: }| - {1:~ }│{1:~}{n: aab }{1: }| - {1:~ }│{1:~}{n: aac }{1: }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {1:~ }│{1:~ }| - {3:<Name] [+] }{4:[No Name] [+] }| - {2:-- }{5:match 1 of 3} | - ]]) - end) - - it('with split and scroll', function() - screen:try_resize(60,14) - command("split") - command("set completeopt+=noinsert") - command("set mouse=a") - insert([[ - Lorem ipsum dolor sit amet, consectetur - adipisicing elit, sed do eiusmod tempor - incididunt ut labore et dolore magna aliqua. - Ut enim ad minim veniam, quis nostrud - exercitation ullamco laboris nisi ut aliquip ex - ea commodo consequat. Duis aute irure dolor in - reprehenderit in voluptate velit esse cillum - dolore eu fugiat nulla pariatur. Excepteur sint - occaecat cupidatat non proident, sunt in culpa - qui officia deserunt mollit anim id est - laborum. - ]]) - - screen:expect([[ - reprehenderit in voluptate velit esse cillum | - dolore eu fugiat nulla pariatur. Excepteur sint | - occaecat cupidatat non proident, sunt in culpa | - qui officia deserunt mollit anim id est | - laborum. | - ^ | - {4:[No Name] [+] }| - Lorem ipsum dolor sit amet, consectetur | - adipisicing elit, sed do eiusmod tempor | - incididunt ut labore et dolore magna aliqua. | - Ut enim ad minim veniam, quis nostrud | - exercitation ullamco laboris nisi ut aliquip ex | - {3:[No Name] [+] }| - | - ]]) - - feed('ggOEst <c-x><c-p>') - screen:expect([[ - Est ^ | - L{n: sunt }{s: }sit amet, consectetur | - a{n: in }{s: }sed do eiusmod tempor | - i{n: culpa }{s: }re et dolore magna aliqua. | - U{n: qui }{s: }eniam, quis nostrud | - e{n: officia }{s: }co laboris nisi ut aliquip ex | - {4:[No}{n: deserunt }{s: }{4: }| - L{n: mollit }{s: }sit amet, consectetur | - a{n: anim }{s: }sed do eiusmod tempor | - i{n: id }{s: }re et dolore magna aliqua. | - U{n: est }{s: }eniam, quis nostrud | - e{n: laborum }{c: }co laboris nisi ut aliquip ex | - {3:[No}{s: Est }{c: }{3: }| - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | - ]]) - - meths.input_mouse('wheel', 'down', '', 0, 9, 40) - screen:expect([[ - Est ^ | - L{n: sunt }{s: }sit amet, consectetur | - a{n: in }{s: }sed do eiusmod tempor | - i{n: culpa }{s: }re et dolore magna aliqua. | - U{n: qui }{s: }eniam, quis nostrud | - e{n: officia }{s: }co laboris nisi ut aliquip ex | - {4:[No}{n: deserunt }{s: }{4: }| - U{n: mollit }{s: }eniam, quis nostrud | - e{n: anim }{s: }co laboris nisi ut aliquip ex | - e{n: id }{s: }at. Duis aute irure dolor in | - r{n: est }{s: }oluptate velit esse cillum | - d{n: laborum }{c: }ulla pariatur. Excepteur sint | - {3:[No}{s: Est }{c: }{3: }| - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | - ]]) - - feed('e') - screen:expect([[ - Est e^ | - L{n: elit } sit amet, consectetur | - a{n: eiusmod } sed do eiusmod tempor | - i{n: et }ore et dolore magna aliqua. | - U{n: enim }veniam, quis nostrud | - e{n: exercitation }mco laboris nisi ut aliquip ex | - {4:[No}{n: ex }{4: }| - U{n: ea }veniam, quis nostrud | - e{n: esse }mco laboris nisi ut aliquip ex | - e{n: eu }uat. Duis aute irure dolor in | - r{s: est }voluptate velit esse cillum | - dolore eu fugiat nulla pariatur. Excepteur sint | - {3:[No Name] [+] }| - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | - ]]) - - meths.input_mouse('wheel', 'up', '', 0, 9, 40) - screen:expect([[ - Est e^ | - L{n: elit } sit amet, consectetur | - a{n: eiusmod } sed do eiusmod tempor | - i{n: et }ore et dolore magna aliqua. | - U{n: enim }veniam, quis nostrud | - e{n: exercitation }mco laboris nisi ut aliquip ex | - {4:[No}{n: ex }{4: }| - L{n: ea } sit amet, consectetur | - a{n: esse } sed do eiusmod tempor | - i{n: eu }ore et dolore magna aliqua. | - U{s: est }veniam, quis nostrud | - exercitation ullamco laboris nisi ut aliquip ex | - {3:[No Name] [+] }| - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | - ]]) - - feed('s') - screen:expect([[ - Est es^ | - L{n: esse } sit amet, consectetur | - a{s: est } sed do eiusmod tempor | - incididunt ut labore et dolore magna aliqua. | - Ut enim ad minim veniam, quis nostrud | - exercitation ullamco laboris nisi ut aliquip ex | - {4:[No Name] [+] }| - Lorem ipsum dolor sit amet, consectetur | - adipisicing elit, sed do eiusmod tempor | - incididunt ut labore et dolore magna aliqua. | - Ut enim ad minim veniam, quis nostrud | - exercitation ullamco laboris nisi ut aliquip ex | - {3:[No Name] [+] }| - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | - ]]) - - meths.input_mouse('wheel', 'down', '', 0, 9, 40) - screen:expect([[ - Est es^ | - L{n: esse } sit amet, consectetur | - a{s: est } sed do eiusmod tempor | - incididunt ut labore et dolore magna aliqua. | - Ut enim ad minim veniam, quis nostrud | - exercitation ullamco laboris nisi ut aliquip ex | - {4:[No Name] [+] }| - Ut enim ad minim veniam, quis nostrud | - exercitation ullamco laboris nisi ut aliquip ex | - ea commodo consequat. Duis aute irure dolor in | - reprehenderit in voluptate velit esse cillum | - dolore eu fugiat nulla pariatur. Excepteur sint | - {3:[No Name] [+] }| - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | - ]]) - - feed('<bs>') - screen:expect([[ - Est e^ | - L{n: elit } sit amet, consectetur | - a{n: eiusmod } sed do eiusmod tempor | - i{n: et }ore et dolore magna aliqua. | - U{n: enim }veniam, quis nostrud | - e{n: exercitation }mco laboris nisi ut aliquip ex | - {4:[No}{n: ex }{4: }| - U{n: ea }veniam, quis nostrud | - e{n: esse }mco laboris nisi ut aliquip ex | - e{n: eu }uat. Duis aute irure dolor in | - r{s: est }voluptate velit esse cillum | - dolore eu fugiat nulla pariatur. Excepteur sint | - {3:[No Name] [+] }| - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | - ]]) - - feed('<c-p>') - screen:expect([[ - Est eu^ | - L{n: elit } sit amet, consectetur | - a{n: eiusmod } sed do eiusmod tempor | - i{n: et }ore et dolore magna aliqua. | - U{n: enim }veniam, quis nostrud | - e{n: exercitation }mco laboris nisi ut aliquip ex | - {4:[No}{n: ex }{4: }| - U{n: ea }veniam, quis nostrud | - e{n: esse }mco laboris nisi ut aliquip ex | - e{s: eu }uat. Duis aute irure dolor in | - r{n: est }voluptate velit esse cillum | - dolore eu fugiat nulla pariatur. Excepteur sint | - {3:[No Name] [+] }| - {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65} | - ]]) - - meths.input_mouse('wheel', 'down', '', 0, 9, 40) - screen:expect([[ - Est eu^ | - L{n: elit } sit amet, consectetur | - a{n: eiusmod } sed do eiusmod tempor | - i{n: et }ore et dolore magna aliqua. | - U{n: enim }veniam, quis nostrud | - e{n: exercitation }mco laboris nisi ut aliquip ex | - {4:[No}{n: ex }{4: }| - r{n: ea }voluptate velit esse cillum | - d{n: esse }nulla pariatur. Excepteur sint | - o{s: eu }t non proident, sunt in culpa | - q{n: est }unt mollit anim id est | - laborum. | - {3:[No Name] [+] }| - {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65} | - ]]) - - - funcs.complete(4, {'ea', 'eeeeeeeeeeeeeeeeee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'}) - screen:expect([[ - Est eu^ | - {s: ea }t amet, consectetur | - {n: eeeeeeeeeeeeeeeeee }d do eiusmod tempor | - {n: ei } et dolore magna aliqua. | - {n: eo }iam, quis nostrud | - {n: eu } laboris nisi ut aliquip ex | - {4:[N}{n: ey }{4: }| - {n: eå }uptate velit esse cillum | - {n: eä }la pariatur. Excepteur sint | - {n: eö }on proident, sunt in culpa | - qui officia deserunt mollit anim id est | - laborum. | - {3:[No Name] [+] }| - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 9} | - ]]) - - funcs.complete(4, {'ea', 'eee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'}) - screen:expect([[ - Est eu^ | - {s: ea }r sit amet, consectetur | - {n: eee }, sed do eiusmod tempor | - {n: ei }bore et dolore magna aliqua. | - {n: eo } veniam, quis nostrud | - {n: eu }amco laboris nisi ut aliquip ex | - {4:[N}{n: ey }{4: }| - {n: eå } voluptate velit esse cillum | - {n: eä } nulla pariatur. Excepteur sint | - {n: eö }at non proident, sunt in culpa | - qui officia deserunt mollit anim id est | - laborum. | - {3:[No Name] [+] }| - {2:-- INSERT --} | - ]]) - - feed('<c-n>') - screen:expect([[ - Esteee^ | - {n: ea }r sit amet, consectetur | - {s: eee }, sed do eiusmod tempor | - {n: ei }bore et dolore magna aliqua. | - {n: eo } veniam, quis nostrud | - {n: eu }amco laboris nisi ut aliquip ex | - {4:[N}{n: ey }{4: }| - {n: eå } voluptate velit esse cillum | - {n: eä } nulla pariatur. Excepteur sint | - {n: eö }at non proident, sunt in culpa | - qui officia deserunt mollit anim id est | - laborum. | - {3:[No Name] [+] }| - {2:-- INSERT --} | - ]]) - - funcs.complete(6, {'foo', 'bar'}) - screen:expect([[ - Esteee^ | - Lo{s: foo }sit amet, consectetur | - ad{n: bar }sed do eiusmod tempor | - incididunt ut labore et dolore magna aliqua. | - Ut enim ad minim veniam, quis nostrud | - exercitation ullamco laboris nisi ut aliquip ex | - {4:[No Name] [+] }| - reprehenderit in voluptate velit esse cillum | - dolore eu fugiat nulla pariatur. Excepteur sint | - occaecat cupidatat non proident, sunt in culpa | - qui officia deserunt mollit anim id est | - laborum. | - {3:[No Name] [+] }| - {2:-- INSERT --} | - ]]) - - feed('<c-y>') - screen:expect([[ - Esteefoo^ | - Lorem ipsum dolor sit amet, consectetur | - adipisicing elit, sed do eiusmod tempor | - incididunt ut labore et dolore magna aliqua. | - Ut enim ad minim veniam, quis nostrud | - exercitation ullamco laboris nisi ut aliquip ex | - {4:[No Name] [+] }| - reprehenderit in voluptate velit esse cillum | - dolore eu fugiat nulla pariatur. Excepteur sint | - occaecat cupidatat non proident, sunt in culpa | - qui officia deserunt mollit anim id est | - laborum. | - {3:[No Name] [+] }| - {2:-- INSERT --} | - ]]) - end) - - it('can be moved due to wrap or resize', function() - feed('isome long prefix before the ') - command("set completeopt+=noinsert,noselect") - command("set linebreak") - funcs.complete(29, {'word', 'choice', 'text', 'thing'}) - screen:expect([[ - some long prefix before the ^ | - {1:~ }{n: word }| - {1:~ }{n: choice}| - {1:~ }{n: text }| - {1:~ }{n: thing }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<c-p>') - screen:expect([[ - some long prefix before the | - thing^ | - {n:word }{1: }| - {n:choice }{1: }| - {n:text }{1: }| - {s:thing }{1: }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<c-p>') - screen:expect([[ - some long prefix before the text| - {1:^~ }{n: word }| - {1:~ }{n: choice}| - {1:~ }{s: text }| - {1:~ }{n: thing }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - screen:try_resize(30,8) - screen:expect([[ - some long prefix before the | - text^ | - {n:word }{1: }| - {n:choice }{1: }| - {s:text }{1: }| - {n:thing }{1: }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - screen:try_resize(50,8) - screen:expect([[ - some long prefix before the text^ | - {1:~ }{n: word }{1: }| - {1:~ }{n: choice }{1: }| - {1:~ }{s: text }{1: }| - {1:~ }{n: thing }{1: }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - screen:try_resize(25,10) - screen:expect([[ - some long prefix before | - the text^ | - {1:~ }{n: word }{1: }| - {1:~ }{n: choice }{1: }| - {1:~ }{s: text }{1: }| - {1:~ }{n: thing }{1: }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - screen:try_resize(12,5) - screen:expect([[ - some long | - prefix | - bef{n: word } | - tex{n: }^ | - {2:-- INSERT -} | - ]]) - - -- can't draw the pum, but check we don't crash - screen:try_resize(12,2) - screen:expect([[ - text^ | - {2:-- INSERT -} | - ]]) - - -- but state is preserved, pum reappears - screen:try_resize(20,8) - screen:expect([[ - some long prefix | - before the text^ | - {1:~ }{n: word }{1: }| - {1:~ }{n: choice }{1: }| - {1:~ }{s: text }{1: }| - {1:~ }{n: thing }{1: }| - {1:~ }| - {2:-- INSERT --} | - ]]) - end) - - it('with VimResized autocmd', function() - feed('isome long prefix before the ') - command("set completeopt+=noinsert,noselect") - command("autocmd VimResized * redraw!") - command("set linebreak") - funcs.complete(29, {'word', 'choice', 'text', 'thing'}) - screen:expect([[ - some long prefix before the ^ | - {1:~ }{n: word }| - {1:~ }{n: choice}| - {1:~ }{n: text }| - {1:~ }{n: thing }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - screen:try_resize(16,10) - screen:expect([[ - some long | - prefix before | - the ^ | - {1:~ }{n: word }| - {1:~ }{n: choice }| - {1:~ }{n: text }| - {1:~ }{n: thing }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - end) - - it('with rightleft window', function() - command("set rl wildoptions+=pum") - feed('isome rightleft ') - screen:expect([[ - ^ tfelthgir emos| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {2:-- INSERT --} | - ]]) - - command("set completeopt+=noinsert,noselect") - funcs.complete(16, {'word', 'choice', 'text', 'thing'}) - screen:expect([[ - ^ tfelthgir emos| - {1: }{n: drow}{1: ~}| - {1: }{n: eciohc}{1: ~}| - {1: }{n: txet}{1: ~}| - {1: }{n: gniht}{1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {2:-- INSERT --} | - ]]) - - feed('<c-n>') - screen:expect([[ - ^ drow tfelthgir emos| - {1: }{s: drow}{1: ~}| - {1: }{n: eciohc}{1: ~}| - {1: }{n: txet}{1: ~}| - {1: }{n: gniht}{1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {2:-- INSERT --} | - ]]) - - feed('<c-y>') - screen:expect([[ - ^ drow tfelthgir emos| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {2:-- INSERT --} | - ]]) - - -- not rightleft on the cmdline - feed('<esc>:sign ') - screen:expect{grid=[[ - drow tfelthgir emos| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - :sign ^ | - ]]} - - feed('<tab>') - screen:expect{grid=[[ - drow tfelthgir emos| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: ~}| - {1: }{s: define }{1: ~}| - {1: }{n: jump }{1: ~}| - {1: }{n: list }{1: ~}| - {1: }{n: place }{1: ~}| - {1: }{n: undefine }{1: ~}| - {1: }{n: unplace }{1: ~}| - :sign define^ | - ]]} - end) - - it('with multiline messages', function() - screen:try_resize(40,8) - feed('ixx<cr>') - command('imap <f2> <cmd>echoerr "very"\\|echoerr "much"\\|echoerr "error"<cr>') - funcs.complete(1, {'word', 'choice', 'text', 'thing'}) - screen:expect([[ - xx | - word^ | - {s:word }{1: }| - {n:choice }{1: }| - {n:text }{1: }| - {n:thing }{1: }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<f2>') - screen:expect([[ - xx | - word | - {s:word }{1: }| - {4: }| - {6:very} | - {6:much} | - {6:error} | - {5:Press ENTER or type command to continue}^ | - ]]) - - feed('<cr>') - screen:expect([[ - xx | - word^ | - {s:word }{1: }| - {n:choice }{1: }| - {n:text }{1: }| - {n:thing }{1: }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<c-n>') - screen:expect([[ - xx | - choice^ | - {n:word }{1: }| - {s:choice }{1: }| - {n:text }{1: }| - {n:thing }{1: }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - command("split") - screen:expect([[ - xx | - choice^ | - {n:word }{1: }| - {s:choice }{4: }| - {n:text } | - {n:thing } | - {3:[No Name] [+] }| - {2:-- INSERT --} | - ]]) - - meths.input_mouse('wheel', 'down', '', 0, 6, 15) - screen:expect{grid=[[ - xx | - choice^ | - {n:word }{1: }| - {s:choice }{4: }| - {n:text } | - {n:thing }{1: }| - {3:[No Name] [+] }| - {2:-- INSERT --} | - ]], unchanged=true} - end) - - it('with kind, menu and abbr attributes', function() - screen:try_resize(40,8) - feed('ixx ') - funcs.complete(4, {{word='wordey', kind= 'x', menu='extrainfo'}, 'thing', {word='secret', abbr='sneaky', menu='bar'}}) - screen:expect([[ - xx wordey^ | - {1:~ }{s: wordey x extrainfo }{1: }| - {1:~ }{n: thing }{1: }| - {1:~ }{n: sneaky bar }{1: }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<c-p>') - screen:expect([[ - xx ^ | - {1:~ }{n: wordey x extrainfo }{1: }| - {1:~ }{n: thing }{1: }| - {1:~ }{n: sneaky bar }{1: }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<c-p>') - screen:expect([[ - xx secret^ | - {1:~ }{n: wordey x extrainfo }{1: }| - {1:~ }{n: thing }{1: }| - {1:~ }{s: sneaky bar }{1: }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<esc>') - screen:expect([[ - xx secre^t | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]) - end) - - it('wildoptions=pum', function() - screen:try_resize(32,10) - command('set wildmenu') - command('set wildoptions=pum') - command('set shellslash') - command("cd test/functional/fixtures/wildpum") - - feed(':sign ') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :sign ^ | - ]]) - - feed('<Tab>') - 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('<Right><Right>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }{n: define }{1: }| - {1:~ }{n: jump }{1: }| - {1:~ }{s: list }{1: }| - {1:~ }{n: place }{1: }| - {1:~ }{n: undefine }{1: }| - {1:~ }{n: unplace }{1: }| - :sign list^ | - ]]) - - feed('<C-N>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }{n: define }{1: }| - {1:~ }{n: jump }{1: }| - {1:~ }{n: list }{1: }| - {1:~ }{s: place }{1: }| - {1:~ }{n: undefine }{1: }| - {1:~ }{n: unplace }{1: }| - :sign place^ | - ]]) - - feed('<C-P>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }{n: define }{1: }| - {1:~ }{n: jump }{1: }| - {1:~ }{s: list }{1: }| - {1:~ }{n: place }{1: }| - {1:~ }{n: undefine }{1: }| - {1:~ }{n: unplace }{1: }| - :sign list^ | - ]]) - - feed('<Left>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }{n: define }{1: }| - {1:~ }{s: jump }{1: }| - {1:~ }{n: list }{1: }| - {1:~ }{n: place }{1: }| - {1:~ }{n: undefine }{1: }| - {1:~ }{n: unplace }{1: }| - :sign jump^ | - ]]) - - -- pressing <C-E> should end completion and go back to the original match - feed('<C-E>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :sign ^ | - ]]) - - -- pressing <C-Y> should select the current match and end completion - feed('<Tab><C-P><C-P><C-Y>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :sign unplace^ | - ]]) - - -- showing popup menu in different columns in the cmdline - feed('<C-U>sign define <Tab>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }{s: culhl= }{1: }| - {1:~ }{n: icon= }{1: }| - {1:~ }{n: linehl= }{1: }| - {1:~ }{n: numhl= }{1: }| - {1:~ }{n: text= }{1: }| - {1:~ }{n: texthl= }{1: }| - :sign define culhl=^ | - ]]) - - feed('<Space><Tab>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }{s: culhl= }{1: }| - {1:~ }{n: icon= }{1: }| - {1:~ }{n: linehl= }{1: }| - {1:~ }{n: numhl= }{1: }| - {1:~ }{n: text= }{1: }| - {1:~ }{n: texthl= }{1: }| - :sign define culhl= culhl=^ | - ]]) - - feed('<C-U>e Xdi<Tab><Tab>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{s: XdirA/ }{1: }| - {1:~ }{n: XfileA }{1: }| - :e Xdir/XdirA/^ | - ]]) - - -- Pressing <Down> on a directory name should go into that directory - feed('<Down>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{s: XdirB/ }{1: }| - {1:~ }{n: XfileB }{1: }| - :e Xdir/XdirA/XdirB/^ | - ]]) - - -- Pressing <Up> on a directory name should go to the parent directory - feed('<Up>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{s: XdirA/ }{1: }| - {1:~ }{n: XfileA }{1: }| - :e Xdir/XdirA/^ | - ]]) - - -- Pressing <C-A> when the popup menu is displayed should list all the - -- matches and remove the popup menu - feed(':<C-U>sign <Tab><C-A>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {4: }| - :sign define jump list place und| - 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>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {4: }| - :sign define | - define | - :sign define^ | - ]]) - - -- Pressing <S-Tab> should open the popup menu with the last entry selected - feed('<C-U><CR>:sign <S-Tab><C-P>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }{n: define }{1: }| - {1:~ }{n: jump }{1: }| - {1:~ }{n: list }{1: }| - {1:~ }{n: place }{1: }| - {1:~ }{s: undefine }{1: }| - {1:~ }{n: unplace }{1: }| - :sign undefine^ | - ]]) - - -- Pressing <Esc> should close the popup menu and cancel the cmd line - feed('<C-U><CR>:sign <Tab><Esc>') - screen:expect([[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]) - - -- Typing a character when the popup is open, should close the popup - feed(':sign <Tab>x') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :sign definex^ | - ]]) - - -- When the popup is open, entering the cmdline window should close the popup - feed('<C-U>sign <Tab><C-F>') - screen:expect([[ - | - {3:[No Name] }| - {1::}sign define | - {1::}sign define^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {4:[Command Line] }| - :sign define | - ]]) - feed(':q<CR>') - - -- After the last popup menu item, <C-N> should show the original string - feed(':sign u<Tab><C-N><C-N>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{n: undefine }{1: }| - {1:~ }{n: unplace }{1: }| - :sign u^ | - ]]) - - -- Use the popup menu for the command name - feed('<C-U>bu<Tab>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {s: bufdo }{1: }| - {n: buffer }{1: }| - {n: buffers }{1: }| - {n: bunload }{1: }| - :bufdo^ | - ]]) - - -- Pressing <BS> should remove the popup menu and erase the last character - feed('<C-E><C-U>sign <Tab><BS>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :sign defin^ | - ]]) - - -- Pressing <C-W> should remove the popup menu and erase the previous word - feed('<C-E><C-U>sign <Tab><C-W>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :sign ^ | - ]]) - - -- Pressing <C-U> should remove the popup menu and erase the entire line - feed('<C-E><C-U>sign <Tab><C-U>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :^ | - ]]) - - -- Using <C-E> to cancel the popup menu and then pressing <Up> should recall - -- the cmdline from history - feed('sign xyz<Esc>:sign <Tab><C-E><Up>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :sign xyz^ | - ]]) - - feed('<esc>') - - -- Check "list" still works - command('set wildmode=longest,list') - feed(':cn<Tab>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {4: }| - :cn | - cnewer cnoreabbrev | - cnext cnoremap | - cnfile cnoremenu | - :cn^ | - ]]) - feed('s') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {4: }| - :cn | - cnewer cnoreabbrev | - cnext cnoremap | - cnfile cnoremenu | - :cns^ | - ]]) - - feed('<esc>') - command('set wildmode=full') - - -- Tests a directory name contained full-width characters. - feed(':e あいう/<Tab>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{s: 123 }{1: }| - {1:~ }{n: abc }{1: }| - {1:~ }{n: xyz }{1: }| - :e あいう/123^ | - ]]) - 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") - command("sp långfile2") - feed(':b lå<tab>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {4:långfile2 }| - | - {1:~ }| - {1:~ }{s: långfile1 }{1: }| - {3:lå}{n: långfile2 }{3: }| - :b långfile1^ | - ]]) - - -- check doesn't crash on screen resize - screen:try_resize(20,6) - screen:expect([[ - | - {1:~ }| - {4:långfile2 }| - {s: långfile1 } | - {3:lå}{n: långfile2 }{3: }| - :b långfile1^ | - ]]) - - screen:try_resize(50,15) - screen:expect([[ - | - {1:~ }| - {4:långfile2 }| - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{s: långfile1 }{1: }| - {3:lå}{n: långfile2 }{3: }| - :b långfile1^ | - ]]) - - -- position is calculated correctly with "longest" - feed('<esc>') - command('set wildmode=longest:full,full') - feed(':b lå<tab>') - screen:expect([[ - | - {1:~ }| - {4:långfile2 }| - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{n: långfile1 }{1: }| - {3:lå}{n: långfile2 }{3: }| - :b långfile^ | - ]]) - - feed('<esc>') - command("close") - command('set wildmode=full') - - -- special case: when patterns ends with "/", show menu items aligned - -- after the "/" - feed(':e compdir/<tab>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{s: file1 }{1: }| - {1:~ }{n: file2 }{1: }| - :e compdir/file1^ | - ]]) - end) - - it('wildoptions=pum with scrolled messages', function() - screen:try_resize(40,10) - command('set wildmenu') - command('set wildoptions=pum') - - feed(':echoerr "fail"|echoerr "error"<cr>') - screen:expect{grid=[[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {4: }| - {6:fail} | - {6:error} | - {5:Press ENTER or type command to continue}^ | - ]]} - - feed(':sign <tab>') - screen:expect{grid=[[ - | - {1:~ }| - {1:~ }| - {1:~ }{s: define }{1: }| - {1:~ }{n: jump }{1: }| - {1:~ }{n: list }{1: }| - {4: }{n: place }{4: }| - {6:fail} {n: undefine } | - {6:error}{n: unplace } | - :sign define^ | - ]]} - - feed('d') - screen:expect{grid=[[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {4: }| - {6:fail} | - {6:error} | - :sign defined^ | - ]]} - end) - - it('wildoptions=pum and wildmode=longest,full #11622', function() - screen:try_resize(30,8) - command('set wildmenu') - command('set wildoptions=pum') - command('set wildmode=longest,full') - - -- With 'wildmode' set to 'longest,full', completing a match should display - -- the longest match, the wildmenu should not be displayed. - feed(':sign u<Tab>') - screen:expect{grid=[[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :sign un^ | - ]]} - eq(0, funcs.wildmenumode()) - - -- pressing <Tab> should display the wildmenu - feed('<Tab>') - screen:expect{grid=[[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{s: undefine }{1: }| - {1:~ }{n: unplace }{1: }| - :sign undefine^ | - ]]} - eq(1, funcs.wildmenumode()) - - -- pressing <Tab> second time should select the next entry in the menu - feed('<Tab>') - screen:expect{grid=[[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }{n: undefine }{1: }| - {1:~ }{s: unplace }{1: }| - :sign unplace^ | - ]]} - end) - - it('wildoptions=pum with a wrapped line in buffer vim-patch:8.2.4655', function() - screen:try_resize(32, 10) - meths.buf_set_lines(0, 0, -1, true, { ('a'):rep(100) }) - command('set wildoptions+=pum') - feed('$') - feed(':sign <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) + it('RGB-color', function() + local screen = Screen.new(60, 14) screen:set_default_attr_ids({ [1] = {background = Screen.colors.Yellow}, [2] = {bold = true, reverse = true}, @@ -2934,6 +1076,7 @@ describe('builtin popupmenu', function() [44] = {foreground = tonumber('0x3f3f3f'), background = tonumber('0x7f5d7f')}, [45] = {background = Screen.colors.WebGray, blend=0}, }) + screen:attach() command('syntax on') command('set mouse=a') command('set pumblend=10') @@ -3082,10 +1225,8 @@ describe('builtin popupmenu', function() ]]) end) - it("'pumblend' 256-color (non-RGB)", function() - screen:detach() - screen = Screen.new(60, 8) - screen:attach({rgb=false, ext_popupmenu=false}) + it('256-color (non-RGB)', function() + local screen = Screen.new(60, 8) screen:set_default_attr_ids({ [1] = {foreground = Screen.colors.Grey0, background = tonumber('0x000007')}, [2] = {foreground = tonumber('0x000055'), background = tonumber('0x000007')}, @@ -3098,6 +1239,7 @@ describe('builtin popupmenu', function() [9] = {bold = true}, [10] = {foreground = tonumber('0x000002')}, }) + screen:attach({rgb=false}) command('set notermguicolors pumblend=10') insert([[ Lorem ipsum dolor sit amet, consectetur @@ -3118,651 +1260,3738 @@ describe('builtin popupmenu', function() {9:-- Keyword Local completion (^N^P) }{10:match 1 of 3} | ]]) end) +end) - it("'pumheight'", function() - screen:try_resize(32,8) - feed('isome long prefix before the ') - command("set completeopt+=noinsert,noselect") - command("set linebreak") - command("set pumheight=2") - funcs.complete(29, {'word', 'choice', 'text', 'thing'}) - screen:expect([[ - some long prefix before the ^ | - {1:~ }{n: word }{c: }| - {1:~ }{n: choice}{s: }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - end) +describe('builtin popupmenu', function() + before_each(clear) + + local function with_ext_multigrid(multigrid) + local screen + before_each(function() + screen = Screen.new(32, 20) + screen:set_default_attr_ids({ + -- popup selected item / scrollbar track + ['s'] = {background = Screen.colors.WebGray}, + -- popup non-selected item + ['n'] = {background = Screen.colors.LightMagenta}, + -- popup scrollbar knob + ['c'] = {background = Screen.colors.Grey0}, + [1] = {bold = true, foreground = Screen.colors.Blue}, + [2] = {bold = true}, + [3] = {reverse = true}, + [4] = {bold = true, reverse = true}, + [5] = {bold = true, foreground = Screen.colors.SeaGreen}, + [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [7] = {background = Screen.colors.Yellow}, -- Search + [8] = {foreground = Screen.colors.Red}, + }) + screen:attach({ext_multigrid=multigrid}) + end) - it("'pumwidth'", function() - screen:try_resize(32,8) - feed('isome long prefix before the ') - command("set completeopt+=noinsert,noselect") - command("set linebreak") - command("set pumwidth=8") - funcs.complete(29, {'word', 'choice', 'text', 'thing'}) - screen:expect([[ - some long prefix before the ^ | - {1:~ }{n: word }| - {1:~ }{n: choice}| - {1:~ }{n: text }| - {1:~ }{n: thing }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - end) + it('with preview-window above', function() + feed(':ped<CR><c-w>4+') + feed('iaa bb cc dd ee ff gg hh ii jj<cr>') + feed('<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + {3:[No Name] [Preview][+] }| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + {4:[No Name] [+] }| + [3:--------------------------------]| + ## grid 2 + aa bb cc dd ee ff gg hh ii jj | + aa^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 1 of 10} | + ## grid 4 + aa bb cc dd ee ff gg hh ii jj | + aa | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 5 + {s:aa }{c: }| + {n:bb }{c: }| + {n:cc }{c: }| + {n:dd }{c: }| + {n:ee }{c: }| + {n:ff }{c: }| + {n:gg }{s: }| + {n:hh }{s: }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 2, 2, 0, false, 100}; + }} + else + screen:expect([[ + aa bb cc dd ee ff gg hh ii jj | + aa | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3:[No Name] [Preview][+] }| + aa bb cc dd ee ff gg hh ii jj | + aa^ | + {s:aa }{c: }{1: }| + {n:bb }{c: }{1: }| + {n:cc }{c: }{1: }| + {n:dd }{c: }{1: }| + {n:ee }{c: }{1: }| + {n:ff }{c: }{1: }| + {n:gg }{s: }{1: }| + {n:hh }{s: }{4: }| + {2:-- }{5:match 1 of 10} | + ]]) + end + end) + + it('with preview-window below', function() + feed(':ped<CR><c-w>4+<c-w>r') + feed('iaa bb cc dd ee ff gg hh ii jj<cr>') + feed('<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + {4:[No Name] [+] }| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + {3:[No Name] [Preview][+] }| + [3:--------------------------------]| + ## grid 2 + aa bb cc dd ee ff gg hh ii jj | + aa^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 1 of 10} | + ## grid 4 + aa bb cc dd ee ff gg hh ii jj | + aa | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 5 + {s:aa }{c: }| + {n:bb }{c: }| + {n:cc }{c: }| + {n:dd }{c: }| + {n:ee }{c: }| + {n:ff }{c: }| + {n:gg }{s: }| + {n:hh }{s: }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 2, 2, 0, false, 100}; + }} + else + screen:expect([[ + aa bb cc dd ee ff gg hh ii jj | + aa^ | + {s:aa }{c: }{1: }| + {n:bb }{c: }{1: }| + {n:cc }{c: }{1: }| + {n:dd }{c: }{1: }| + {n:ee }{c: }{1: }| + {n:ff }{c: }{1: }| + {n:gg }{s: }{1: }| + {n:hh }{s: }{4: }| + aa bb cc dd ee ff gg hh ii jj | + aa | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3:[No Name] [Preview][+] }| + {2:-- }{5:match 1 of 10} | + ]]) + end + end) + + it('with preview-window above and tall and inverted', function() + feed(':ped<CR><c-w>8+') + feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>') + feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>') + feed('kk<cr>ll<cr>mm<cr>nn<cr>oo<cr>') + feed('<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + {3:[No Name] [Preview][+] }| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + {4:[No Name] [+] }| + [3:--------------------------------]| + ## grid 2 + dd | + ee | + ff | + gg | + hh | + ii | + jj | + kk | + ll | + mm | + nn | + oo | + aa^ | + ## grid 3 + {2:-- }{5:match 1 of 15} | + ## grid 4 + aa | + bb | + cc | + dd | + ## grid 5 + {s:aa }{c: }| + {n:bb }{c: }| + {n:cc }{c: }| + {n:dd }{c: }| + {n:ee }{c: }| + {n:ff }{c: }| + {n:gg }{c: }| + {n:hh }{c: }| + {n:ii }{c: }| + {n:jj }{c: }| + {n:kk }{c: }| + {n:ll }{s: }| + {n:mm }{s: }| + ]], float_pos={ + [5] = {{id = -1}, "SW", 2, 12, 0, false, 100}; + }} + else + screen:expect([[ + aa | + bb | + cc | + dd | + {s:aa }{c: }{3:ew][+] }| + {n:bb }{c: } | + {n:cc }{c: } | + {n:dd }{c: } | + {n:ee }{c: } | + {n:ff }{c: } | + {n:gg }{c: } | + {n:hh }{c: } | + {n:ii }{c: } | + {n:jj }{c: } | + {n:kk }{c: } | + {n:ll }{s: } | + {n:mm }{s: } | + aa^ | + {4:[No Name] [+] }| + {2:-- }{5:match 1 of 15} | + ]]) + end + end) + + it('with preview-window above and short and inverted', function() + feed(':ped<CR><c-w>4+') + feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>') + feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>') + feed('<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + {3:[No Name] [Preview][+] }| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + {4:[No Name] [+] }| + [3:--------------------------------]| + ## grid 2 + cc | + dd | + ee | + ff | + gg | + hh | + ii | + jj | + aa^ | + ## grid 3 + {2:-- }{5:match 1 of 10} | + ## grid 4 + aa | + bb | + cc | + dd | + ee | + ff | + gg | + hh | + ## grid 5 + {s:aa }{c: }| + {n:bb }{c: }| + {n:cc }{c: }| + {n:dd }{c: }| + {n:ee }{c: }| + {n:ff }{c: }| + {n:gg }{c: }| + {n:hh }{c: }| + {n:ii }{s: }| + ]], float_pos={ + [5] = {{id = -1}, "SW", 2, 8, 0, false, 100}; + }} + else + screen:expect([[ + aa | + bb | + cc | + dd | + ee | + ff | + gg | + hh | + {s:aa }{c: }{3:ew][+] }| + {n:bb }{c: } | + {n:cc }{c: } | + {n:dd }{c: } | + {n:ee }{c: } | + {n:ff }{c: } | + {n:gg }{c: } | + {n:hh }{c: } | + {n:ii }{s: } | + aa^ | + {4:[No Name] [+] }| + {2:-- }{5:match 1 of 10} | + ]]) + end + end) - it('does not crash when displayed in the last column with rightleft (#12032)', function() - local col = 30 - local items = {'word', 'choice', 'text', 'thing'} - local max_len = 0 - for _, v in ipairs(items) do - max_len = max_len < #v and #v or max_len + it('with preview-window below and inverted', function() + feed(':ped<CR><c-w>4+<c-w>r') + feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>') + feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>') + feed('<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + {4:[No Name] [+] }| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + [4:--------------------------------]| + {3:[No Name] [Preview][+] }| + [3:--------------------------------]| + ## grid 2 + cc | + dd | + ee | + ff | + gg | + hh | + ii | + jj | + aa^ | + ## grid 3 + {2:-- }{5:match 1 of 10} | + ## grid 4 + aa | + bb | + cc | + dd | + ee | + ff | + gg | + hh | + ## grid 5 + {s:aa }{c: }| + {n:bb }{c: }| + {n:cc }{c: }| + {n:dd }{c: }| + {n:ee }{c: }| + {n:ff }{c: }| + {n:gg }{s: }| + {n:hh }{s: }| + ]], float_pos={ + [5] = {{id = -1}, "SW", 2, 8, 0, false, 100}; + }} + else + screen:expect([[ + {s:aa }{c: } | + {n:bb }{c: } | + {n:cc }{c: } | + {n:dd }{c: } | + {n:ee }{c: } | + {n:ff }{c: } | + {n:gg }{s: } | + {n:hh }{s: } | + aa^ | + {4:[No Name] [+] }| + aa | + bb | + cc | + dd | + ee | + ff | + gg | + hh | + {3:[No Name] [Preview][+] }| + {2:-- }{5:match 1 of 10} | + ]]) + end + end) + + if not multigrid then + -- oldtest: Test_pum_with_preview_win() + it('preview window opened during completion', function() + exec([[ + funct Omni_test(findstart, base) + if a:findstart + return col(".") - 1 + endif + return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}] + endfunc + set omnifunc=Omni_test + set completeopt+=longest + ]]) + feed('Gi<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) + + -- oldtest: Test_scrollbar_on_wide_char() + it('scrollbar overwrites half of double-width char below properly', function() + screen:try_resize(32, 10) + exec([[ + call setline(1, ['a', ' 啊啊啊', + \ ' 哦哦哦', + \ ' 呃呃呃']) + call setline(5, range(10)->map({i, v -> 'aa' .. v .. 'bb'})) + ]]) + feed('A<C-X><C-N>') + screen:expect([[ + aa0bb^ | + {s:aa0bb }{c: }啊 | + {n:aa1bb }{c: } 哦 | + {n:aa2bb }{c: }呃呃 | + {n:aa3bb }{c: } | + {n:aa4bb }{c: } | + {n:aa5bb }{c: } | + {n:aa6bb }{s: } | + {n:aa7bb }{s: } | + {2:-- }{5:match 1 of 10} | + ]]) + end) end - screen:try_resize(col, 8) - command('set rightleft') - command('call setline(1, repeat(" ", &columns - '..max_len..'))') - feed('$i') - funcs.complete(col - max_len, items) - feed('<c-y>') - assert_alive() - end) - it('truncates double-width character correctly when there is no scrollbar', function() - screen:try_resize(32,8) - command('set completeopt+=menuone,noselect') - feed('i' .. string.rep(' ', 13)) - funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'}) - screen:expect([[ - ^ | - {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - end) + it('with vsplits', function() + screen:try_resize(32, 8) + insert('aaa aab aac\n') + feed(':vsplit<cr>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + {4:[No Name] [+] }{3:<Name] [+] }| + [3:--------------------------------]| + ## grid 2 + aaa aab aac| + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :vsplit | + ## grid 4 + aaa aab aac | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + else + screen:expect([[ + aaa aab aac │aaa aab aac| + ^ │ | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {4:[No Name] [+] }{3:<Name] [+] }| + :vsplit | + ]]) + end + + feed('ibbb a<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + [4:--------------------]│[2:-----------]| + {4:[No Name] [+] }{3:<Name] [+] }| + [3:--------------------------------]| + ## grid 2 + aaa aab aac| + bbb aaa | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 4 + aaa aab aac | + bbb aaa^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 5 + {s: aaa }| + {n: aab }| + {n: aac }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 4, 2, 3, false, 100}; + }} + else + screen:expect([[ + aaa aab aac │aaa aab aac| + bbb aaa^ │bbb aaa | + {1:~ }{s: aaa }{1: }│{1:~ }| + {1:~ }{n: aab }{1: }│{1:~ }| + {1:~ }{n: aac }{1: }│{1:~ }| + {1:~ }│{1:~ }| + {4:[No Name] [+] }{3:<Name] [+] }| + {2:-- }{5:match 1 of 3} | + ]]) + end + + feed('<esc><c-w><c-w>oc a<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + {3:<Name] [+] }{4:[No Name] [+] }| + [3:--------------------------------]| + ## grid 2 + aaa aab aac | + bbb aaa | + c aaa^ | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 4 + aaa aab aac| + bbb aaa | + c aaa | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 5 + {s: aaa }| + {n: aab }| + {n: aac }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 2, 3, 1, false, 100}; + }} + else + screen:expect([[ + aaa aab aac│aaa aab aac | + bbb aaa │bbb aaa | + c aaa │c aaa^ | + {1:~ }│{1:~}{s: aaa }{1: }| + {1:~ }│{1:~}{n: aab }{1: }| + {1:~ }│{1:~}{n: aac }{1: }| + {3:<Name] [+] }{4:[No Name] [+] }| + {2:-- }{5:match 1 of 3} | + ]]) + end + + feed('bcdef ccc a<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + {3:<Name] [+] }{4:[No Name] [+] }| + [3:--------------------------------]| + ## grid 2 + aaa aab aac | + bbb aaa | + c aaabcdef ccc aaa^ | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 1 of 4} | + ## grid 4 + aaa aab aac| + bbb aaa | + c aaabcdef | + ccc aaa | + {1:~ }| + {1:~ }| + ## grid 5 + {s: aaa }| + {n: aab }| + {n: aac }| + {n: aaabcdef}| + ]], float_pos={ + [5] = {{id = -1}, "NW", 2, 3, 11, false, 100}; + }} + else + screen:expect([[ + aaa aab aac│aaa aab aac | + bbb aaa │bbb aaa | + c aaabcdef │c aaabcdef ccc aaa^ | + ccc aaa │{1:~ }{s: aaa }| + {1:~ }│{1:~ }{n: aab }| + {1:~ }│{1:~ }{n: aac }| + {3:<Name] [+] }{4:[No Name] [}{n: aaabcdef}| + {2:-- }{5:match 1 of 4} | + ]]) + end + + feed('\n<c-x><c-n>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + [4:-----------]│[2:--------------------]| + {3:<Name] [+] }{4:[No Name] [+] }| + [3:--------------------------------]| + ## grid 2 + aaa aab aac | + bbb aaa | + c aaabcdef ccc aaa | + aaa^ | + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 1 of 6} | + ## grid 4 + aaa aab aac| + bbb aaa | + c aaabcdef | + ccc aaa | + aaa | + {1:~ }| + ## grid 5 + {s: aaa }{c: }| + {n: aab }{s: }| + {n: aac }{s: }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 2, 4, -1, false, 100}; + }} + else + screen:expect([[ + aaa aab aac│aaa aab aac | + bbb aaa │bbb aaa | + c aaabcdef │c aaabcdef ccc aaa | + ccc aaa │aaa^ | + aaa {s: aaa }{c: }{1: }| + {1:~ }{n: aab }{s: }{1: }| + {3:<Name] [+] }{n: aac }{s: }{4: }| + {2:-- }{5:match 1 of 6} | + ]]) + end + end) - it('truncates double-width character correctly when there is scrollbar', function() - screen:try_resize(32,8) - command('set completeopt+=noselect') - command('set pumheight=4') - feed('i' .. string.rep(' ', 12)) - local items = {} - for _ = 1, 8 do - table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1}) + if not multigrid then + it('with split and scroll', function() + screen:try_resize(60,14) + command("split") + command("set completeopt+=noinsert") + command("set mouse=a") + insert([[ + Lorem ipsum dolor sit amet, consectetur + adipisicing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud + exercitation ullamco laboris nisi ut aliquip ex + ea commodo consequat. Duis aute irure dolor in + reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa + qui officia deserunt mollit anim id est + laborum. + ]]) + + screen:expect([[ + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum. | + ^ | + {4:[No Name] [+] }| + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {3:[No Name] [+] }| + | + ]]) + + feed('ggOEst <c-x><c-p>') + screen:expect([[ + Est ^ | + L{n: sunt }{s: }sit amet, consectetur | + a{n: in }{s: }sed do eiusmod tempor | + i{n: culpa }{s: }re et dolore magna aliqua. | + U{n: qui }{s: }eniam, quis nostrud | + e{n: officia }{s: }co laboris nisi ut aliquip ex | + {4:[No}{n: deserunt }{s: }{4: }| + Est{n: mollit }{s: } | + L{n: anim }{s: }sit amet, consectetur | + a{n: id }{s: }sed do eiusmod tempor | + i{n: est }{s: }re et dolore magna aliqua. | + U{n: laborum }{c: }eniam, quis nostrud | + {3:[No}{s: Est }{c: }{3: }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 9, 40) + screen:expect([[ + Est ^ | + L{n: sunt }{s: }sit amet, consectetur | + a{n: in }{s: }sed do eiusmod tempor | + i{n: culpa }{s: }re et dolore magna aliqua. | + U{n: qui }{s: }eniam, quis nostrud | + e{n: officia }{s: }co laboris nisi ut aliquip ex | + {4:[No}{n: deserunt }{s: }{4: }| + i{n: mollit }{s: }re et dolore magna aliqua. | + U{n: anim }{s: }eniam, quis nostrud | + e{n: id }{s: }co laboris nisi ut aliquip ex | + e{n: est }{s: }at. Duis aute irure dolor in | + r{n: laborum }{c: }oluptate velit esse cillum | + {3:[No}{s: Est }{c: }{3: }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + feed('e') + screen:expect([[ + Est e^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + i{n: ea }ore et dolore magna aliqua. | + U{n: esse }veniam, quis nostrud | + e{n: eu }mco laboris nisi ut aliquip ex | + e{s: est }uat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + meths.input_mouse('wheel', 'up', '', 0, 9, 40) + screen:expect([[ + Est e^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + Est{n: ea } | + L{n: esse } sit amet, consectetur | + a{n: eu } sed do eiusmod tempor | + i{s: est }ore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + feed('s') + screen:expect([[ + Est es^ | + L{n: esse } sit amet, consectetur | + a{s: est } sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {4:[No Name] [+] }| + Est es | + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 9, 40) + screen:expect([[ + Est es^ | + L{n: esse } sit amet, consectetur | + a{s: est } sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {4:[No Name] [+] }| + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + feed('<bs>') + screen:expect([[ + Est e^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + i{n: ea }ore et dolore magna aliqua. | + U{n: esse }veniam, quis nostrud | + e{n: eu }mco laboris nisi ut aliquip ex | + e{s: est }uat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + feed('<c-p>') + screen:expect([[ + Est eu^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + i{n: ea }ore et dolore magna aliqua. | + U{n: esse }veniam, quis nostrud | + e{s: eu }mco laboris nisi ut aliquip ex | + e{n: est }uat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 9, 40) + screen:expect([[ + Est eu^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + e{n: ea }uat. Duis aute irure dolor in | + r{n: esse }voluptate velit esse cillum | + d{s: eu }nulla pariatur. Excepteur sint | + o{n: est }t non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65} | + ]]) + + funcs.complete(4, {'ea', 'eeeeeeeeeeeeeeeeee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'}) + screen:expect([[ + Est eu^ | + {s: ea }t amet, consectetur | + {n: eeeeeeeeeeeeeeeeee }d do eiusmod tempor | + {n: ei } et dolore magna aliqua. | + {n: eo }iam, quis nostrud | + {n: eu } laboris nisi ut aliquip ex | + {4:[N}{n: ey }{4: }| + {n: eå }. Duis aute irure dolor in | + {n: eä }uptate velit esse cillum | + {n: eö }la pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 9} | + ]]) + + funcs.complete(4, {'ea', 'eee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'}) + screen:expect([[ + Est eu^ | + {s: ea }r sit amet, consectetur | + {n: eee }, sed do eiusmod tempor | + {n: ei }bore et dolore magna aliqua. | + {n: eo } veniam, quis nostrud | + {n: eu }amco laboris nisi ut aliquip ex | + {4:[N}{n: ey }{4: }| + {n: eå }quat. Duis aute irure dolor in | + {n: eä } voluptate velit esse cillum | + {n: eö } nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + + feed('<c-n>') + screen:expect([[ + Esteee^ | + {n: ea }r sit amet, consectetur | + {s: eee }, sed do eiusmod tempor | + {n: ei }bore et dolore magna aliqua. | + {n: eo } veniam, quis nostrud | + {n: eu }amco laboris nisi ut aliquip ex | + {4:[N}{n: ey }{4: }| + {n: eå }quat. Duis aute irure dolor in | + {n: eä } voluptate velit esse cillum | + {n: eö } nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + + funcs.complete(6, {'foo', 'bar'}) + screen:expect([[ + Esteee^ | + Lo{s: foo }sit amet, consectetur | + ad{n: bar }sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {4:[No Name] [+] }| + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + + feed('<c-y>') + screen:expect([[ + Esteefoo^ | + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {4:[No Name] [+] }| + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + end) + + it('can be moved due to wrap or resize', function() + feed('isome long prefix before the ') + command("set completeopt+=noinsert,noselect") + command("set linebreak") + funcs.complete(29, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + some long prefix before the ^ | + {1:~ }{n: word }| + {1:~ }{n: choice}| + {1:~ }{n: text }| + {1:~ }{n: thing }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-p>') + screen:expect([[ + some long prefix before the | + thing^ | + {n:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {s:thing }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-p>') + screen:expect([[ + some long prefix before the text| + {1:^~ }{n: word }| + {1:~ }{n: choice}| + {1:~ }{s: text }| + {1:~ }{n: thing }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(30,8) + screen:expect([[ + some long prefix before the | + text^ | + {n:word }{1: }| + {n:choice }{1: }| + {s:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(50,8) + screen:expect([[ + some long prefix before the text^ | + {1:~ }{n: word }{1: }| + {1:~ }{n: choice }{1: }| + {1:~ }{s: text }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(25,10) + screen:expect([[ + some long prefix before | + the text^ | + {1:~ }{n: word }{1: }| + {1:~ }{n: choice }{1: }| + {1:~ }{s: text }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(12,5) + screen:expect([[ + some long | + prefix | + bef{n: word } | + tex{n: }^ | + {2:-- INSERT --}| + ]]) + + -- can't draw the pum, but check we don't crash + screen:try_resize(12,2) + screen:expect([[ + {1:<<<}t^ | + {2:-- INSERT --}| + ]]) + + -- but state is preserved, pum reappears + screen:try_resize(20,8) + screen:expect([[ + some long prefix | + before the text^ | + {1:~ }{n: word }{1: }| + {1:~ }{n: choice }{1: }| + {1:~ }{s: text }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end) + + it('with VimResized autocmd', function() + feed('isome long prefix before the ') + command("set completeopt+=noinsert,noselect") + command("autocmd VimResized * redraw!") + command("set linebreak") + funcs.complete(29, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + some long prefix before the ^ | + {1:~ }{n: word }| + {1:~ }{n: choice}| + {1:~ }{n: text }| + {1:~ }{n: thing }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(16,10) + screen:expect([[ + some long | + prefix before | + the ^ | + {1:~ }{n: word }| + {1:~ }{n: choice }| + {1:~ }{n: text }| + {1:~ }{n: thing }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end) + + it('with rightleft window', function() + command("set rl wildoptions+=pum") + feed('isome rightleft ') + screen:expect([[ + ^ tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {2:-- INSERT --} | + ]]) + + command("set completeopt+=noinsert,noselect") + funcs.complete(16, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + ^ tfelthgir emos| + {1: }{n: drow }{1: ~}| + {1: }{n: eciohc }{1: ~}| + {1: }{n: txet }{1: ~}| + {1: }{n: gniht }{1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {2:-- INSERT --} | + ]]) + + feed('<c-n>') + screen:expect([[ + ^ drow tfelthgir emos| + {1: }{s: drow }{1: ~}| + {1: }{n: eciohc }{1: ~}| + {1: }{n: txet }{1: ~}| + {1: }{n: gniht }{1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {2:-- INSERT --} | + ]]) + + feed('<c-y>') + screen:expect([[ + ^ drow tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {2:-- INSERT --} | + ]]) + + -- not rightleft on the cmdline + feed('<esc>:sign ') + screen:expect{grid=[[ + drow tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + :sign ^ | + ]]} + + feed('<tab>') + screen:expect{grid=[[ + drow tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: }{s: define }{1: ~}| + {1: }{n: jump }{1: ~}| + {1: }{n: list }{1: ~}| + {1: }{n: place }{1: ~}| + {1: }{n: undefine }{1: ~}| + {1: }{n: unplace }{1: ~}| + :sign define^ | + ]]} + end) end - funcs.complete(13, items) - screen:expect([[ - ^ | - {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{c: }| - {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{c: }| - {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{s: }| - {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{s: }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - end) - it('supports mousemodel=popup', function() - screen:try_resize(32, 6) - exec([[ - call setline(1, 'popup menu test') - set mouse=a mousemodel=popup + it('with rightleft vsplits', function() + screen:try_resize(40, 6) + command('set rightleft') + command('rightbelow vsplit') + command('set completeopt+=noinsert,noselect') + command('set pumheight=2') + feed('isome rightleft ') + funcs.complete(16, {'word', 'choice', 'text', 'thing'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + {3:[No Name] [+] }{4:[No Name] [+] }| + [3:----------------------------------------]| + ## grid 2 + tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + ## grid 3 + {2:-- INSERT --} | + ## grid 4 + ^ tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + ## grid 5 + {c: }{n: drow }| + {s: }{n: eciohc }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 4, 1, -11, false, 100}; + }} + else + screen:expect([[ + tfelthgir emos│ ^ tfelthgir emos| + {1: }{c: }{n: drow }{1: ~}| + {1: }{s: }{n: eciohc }{1: ~}| + {1: ~}│{1: ~}| + {3:[No Name] [+] }{4:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + end + feed('<C-E><CR>') + funcs.complete(1, {'word', 'choice', 'text', 'thing'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + {3:[No Name] [+] }{4:[No Name] [+] }| + [3:----------------------------------------]| + ## grid 2 + tfelthgir emos| + | + {1: ~}| + {1: ~}| + ## grid 3 + {2:-- INSERT --} | + ## grid 4 + tfelthgir emos| + ^ | + {1: ~}| + {1: ~}| + ## grid 5 + {c: }{n: drow}| + {s: }{n: eciohc}| + ]], float_pos={ + [5] = {{id = -1}, "NW", 4, 2, 4, false, 100}; + }} + else + screen:expect([[ + tfelthgir emos│ tfelthgir emos| + │ ^ | + {1: ~}│{1: }{c: }{n: drow}| + {1: ~}│{1: }{s: }{n: eciohc}| + {3:[No Name] [+] }{4:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + end + feed('<C-E>') + async_meths.call_function('input', {'', '', 'sign'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + {3:[No Name] [+] }{4:[No Name] [+] }| + [3:----------------------------------------]| + ## grid 2 + tfelthgir emos| + | + {1: ~}| + {1: ~}| + ## grid 3 + ^ | + ## grid 4 + tfelthgir emos| + | + {1: ~}| + {1: ~}| + ]]} + else + screen:expect([[ + tfelthgir emos│ tfelthgir emos| + │ | + {1: ~}│{1: ~}| + {1: ~}│{1: ~}| + {3:[No Name] [+] }{4:[No Name] [+] }| + ^ | + ]]) + end + command('set wildoptions+=pum') + feed('<Tab>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + [2:-------------------]│[4:--------------------]| + {3:[No Name] [+] }{4:[No Name] [+] }| + [3:----------------------------------------]| + ## grid 2 + tfelthgir emos| + | + {1: ~}| + {1: ~}| + ## grid 3 + define^ | + ## grid 4 + tfelthgir emos| + | + {1: ~}| + {1: ~}| + ## grid 5 + {s:define }{c: }| + {n:jump }{s: }| + ]], float_pos={ + [5] = {{id = -1}, "SW", 1, 5, 0, false, 250}; + }} + else + screen:expect([[ + tfelthgir emos│ tfelthgir emos| + │ | + {1: ~}│{1: ~}| + {s:define }{c: }{1: ~}│{1: ~}| + {n:jump }{s: }{3: }{4:[No Name] [+] }| + define^ | + ]]) + end + end) - 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('<RightMouse><4,0>') - screen:expect([[ - ^popup menu test | - {1:~ }{n: foo }{1: }| - {1:~ }{n: bar }{1: }| - {1:~ }{n: baz }{1: }| - {1:~ }| - | - ]]) - feed('<Down>') - screen:expect([[ - ^popup menu test | - {1:~ }{s: foo }{1: }| - {1:~ }{n: bar }{1: }| - {1:~ }{n: baz }{1: }| - {1:~ }| - | - ]]) - feed('<Down>') - screen:expect([[ - ^popup menu test | - {1:~ }{n: foo }{1: }| - {1:~ }{s: bar }{1: }| - {1:~ }{n: baz }{1: }| - {1:~ }| - | - ]]) - feed('<CR>') - screen:expect([[ - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :let g:menustr = 'bar' | - ]]) - eq('bar', meths.get_var('menustr')) - feed('<RightMouse><20,1>') - screen:expect([[ - ^popup menu test | - {1:~ }| - {1:~ }{n: foo }{1: }| - {1:~ }{n: bar }{1: }| - {1:~ }{n: baz }{1: }| - :let g:menustr = 'bar' | - ]]) - feed('<LeftMouse><22,4>') - screen:expect([[ - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :let g:menustr = 'baz' | - ]]) - eq('baz', meths.get_var('menustr')) - 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 = 'baz' | - ]]) - feed('<RightDrag><6,3>') - screen:expect([[ - ^popup menu test | - {1:~ }{n: foo }{1: }| - {1:~ }{n: bar }{1: }| - {1:~ }{s: baz }{1: }| - {1:~ }| - :let g:menustr = 'baz' | - ]]) - feed('<RightRelease><6,1>') - screen:expect([[ - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :let g:menustr = 'foo' | - ]]) - eq('foo', meths.get_var('menustr')) - eq(false, screen.options.mousemoveevent) - feed('<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) + if not multigrid then + it('with multiline messages', function() + screen:try_resize(40,8) + feed('ixx<cr>') + command('imap <f2> <cmd>echoerr "very"\\|echoerr "much"\\|echoerr "error"<cr>') + funcs.complete(1, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + xx | + word^ | + {s:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<f2>') + screen:expect([[ + xx | + word | + {s:word }{1: }| + {4: }| + {6:very} | + {6:much} | + {6:error} | + {5:Press ENTER or type command to continue}^ | + ]]) + + feed('<cr>') + screen:expect([[ + xx | + word^ | + {s:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-n>') + screen:expect([[ + xx | + choice^ | + {n:word }{1: }| + {s:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + command("split") + screen:expect([[ + xx | + choice^ | + {n:word }{1: }| + {s:choice }{4: }| + {n:text } | + {n:thing } | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 6, 15) + screen:expect{grid=[[ + xx | + choice^ | + {n:word }{1: }| + {s:choice }{4: }| + {n:text } | + {n:thing }{1: }| + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]], unchanged=true} + end) + + it('with kind, menu and abbr attributes', function() + screen:try_resize(40,8) + feed('ixx ') + funcs.complete(4, {{word='wordey', kind= 'x', menu='extrainfo'}, 'thing', {word='secret', abbr='sneaky', menu='bar'}}) + screen:expect([[ + xx wordey^ | + {1:~ }{s: wordey x extrainfo }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }{n: sneaky bar }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-p>') + screen:expect([[ + xx ^ | + {1:~ }{n: wordey x extrainfo }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }{n: sneaky bar }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-p>') + screen:expect([[ + xx secret^ | + {1:~ }{n: wordey x extrainfo }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }{s: sneaky bar }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<esc>') + screen:expect([[ + xx secre^t | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) + + it('wildoptions=pum', function() + screen:try_resize(32,10) + command('set wildmenu') + command('set wildoptions=pum') + command('set shellslash') + command("cd test/functional/fixtures/wildpum") + + feed(':sign ') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]]) + + feed('<Tab>') + 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('<Right><Right>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{s: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign list^ | + ]]) + + feed('<C-N>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{s: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign place^ | + ]]) + + feed('<C-P>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{s: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign list^ | + ]]) + + feed('<Left>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{s: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign jump^ | + ]]) + + -- pressing <C-E> should end completion and go back to the original match + feed('<C-E>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]]) + + -- pressing <C-Y> should select the current match and end completion + feed('<Tab><C-P><C-P><C-Y>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace^ | + ]]) + + -- showing popup menu in different columns in the cmdline + feed('<C-U>sign define <Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: culhl= }{1: }| + {1:~ }{n: icon= }{1: }| + {1:~ }{n: linehl= }{1: }| + {1:~ }{n: numhl= }{1: }| + {1:~ }{n: text= }{1: }| + {1:~ }{n: texthl= }{1: }| + :sign define culhl=^ | + ]]) + + feed('<Space><Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: culhl= }{1: }| + {1:~ }{n: icon= }{1: }| + {1:~ }{n: linehl= }{1: }| + {1:~ }{n: numhl= }{1: }| + {1:~ }{n: text= }{1: }| + {1:~ }{n: texthl= }{1: }| + :sign define culhl= culhl=^ | + ]]) + + feed('<C-U>e Xnamedi<Tab><Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: XdirA/ }{1: }| + {1:~ }{n: XfileA }{1: }| + :e Xnamedir/XdirA/^ | + ]]) + + -- Pressing <Down> on a directory name should go into that directory + feed('<Down>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: XdirB/ }{1: }| + {1:~ }{n: XfileB }{1: }| + :e Xnamedir/XdirA/XdirB/^ | + ]]) + + -- Pressing <Up> on a directory name should go to the parent directory + feed('<Up>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: XdirA/ }{1: }| + {1:~ }{n: XfileA }{1: }| + :e Xnamedir/XdirA/^ | + ]]) + + -- Pressing <C-A> when the popup menu is displayed should list all the + -- matches and remove the popup menu + feed(':<C-U>sign <Tab><C-A>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + :sign define jump list place und| + 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>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + :sign define | + define | + :sign define^ | + ]]) + + -- Pressing <S-Tab> should open the popup menu with the last entry selected + feed('<C-U><CR>:sign <S-Tab><C-P>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{s: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign undefine^ | + ]]) + + -- Pressing <Esc> should close the popup menu and cancel the cmd line + feed('<C-U><CR>:sign <Tab><Esc>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + + -- Typing a character when the popup is open, should close the popup + feed(':sign <Tab>x') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign definex^ | + ]]) + + -- When the popup is open, entering the cmdline window should close the popup + feed('<C-U>sign <Tab><C-F>') + screen:expect([[ + | + {3:[No Name] }| + {1::}sign define | + {1::}sign defin^e | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {4:[Command Line] }| + :sign define | + ]]) + feed(':q<CR>') + + -- After the last popup menu item, <C-N> should show the original string + feed(':sign u<Tab><C-N><C-N>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign u^ | + ]]) + + -- Use the popup menu for the command name + feed('<C-U>bu<Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {s: bufdo }{1: }| + {n: buffer }{1: }| + {n: buffers }{1: }| + {n: bunload }{1: }| + :bufdo^ | + ]]) + + -- Pressing <BS> should remove the popup menu and erase the last character + feed('<C-E><C-U>sign <Tab><BS>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign defin^ | + ]]) + + -- Pressing <C-W> should remove the popup menu and erase the previous word + feed('<C-E><C-U>sign <Tab><C-W>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]]) + + -- Pressing <C-U> should remove the popup menu and erase the entire line + feed('<C-E><C-U>sign <Tab><C-U>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :^ | + ]]) + + -- Using <C-E> to cancel the popup menu and then pressing <Up> should recall + -- the cmdline from history + feed('sign xyz<Esc>:sign <Tab><C-E><Up>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign xyz^ | + ]]) + + feed('<esc>') + + -- Check "list" still works + command('set wildmode=longest,list') + feed(':cn<Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + :cn | + cnewer cnoreabbrev | + cnext cnoremap | + cnfile cnoremenu | + :cn^ | + ]]) + feed('s') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + :cn | + cnewer cnoreabbrev | + cnext cnoremap | + cnfile cnoremenu | + :cns^ | + ]]) + + feed('<esc>') + command('set wildmode=full') + + -- Tests a directory name contained full-width characters. + feed(':e あいう/<Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: 123 }{1: }| + {1:~ }{n: abc }{1: }| + {1:~ }{n: xyz }{1: }| + :e あいう/123^ | + ]]) + 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^ | + ]]) + + -- pressing <C-E> to end completion should work in middle of the line too + feed('<Esc>:set wildchazz<Left><Left><Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: wildchar }{1: }| + {1:~ }{n: wildcharm }{1: }| + :set wildchar^zz | + ]]) + feed('<C-E>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :set wildcha^zz | + ]]) + + -- pressing <C-Y> should select the current match and end completion + feed('<Esc>:set wildchazz<Left><Left><Tab><C-Y>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :set wildchar^zz | + ]]) + + feed('<Esc>') + + -- check positioning with multibyte char in pattern + command("e långfile1") + command("sp långfile2") + feed(':b lå<tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }{s: långfile1 }{1: }| + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + + -- check doesn't crash on screen resize + screen:try_resize(20,6) + screen:expect([[ + | + {1:~ }| + {4:långfile2 }| + {s: långfile1 } | + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + + screen:try_resize(50,15) + screen:expect([[ + | + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: långfile1 }{1: }| + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + + -- position is calculated correctly with "longest" + feed('<esc>') + command('set wildmode=longest:full,full') + feed(':b lå<tab>') + screen:expect([[ + | + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{n: långfile1 }{1: }| + {3:lå}{n: långfile2 }{3: }| + :b långfile^ | + ]]) + + feed('<esc>') + command("close") + command('set wildmode=full') + + -- special case: when patterns ends with "/", show menu items aligned + -- after the "/" + feed(':e compdir/<tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: file1 }{1: }| + {1:~ }{n: file2 }{1: }| + :e compdir/file1^ | + ]]) + end) + + it('wildoptions=pum with scrolled messages', function() + screen:try_resize(40,10) + command('set wildmenu') + command('set wildoptions=pum') + + feed(':echoerr "fail"|echoerr "error"<cr>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + {6:fail} | + {6:error} | + {5:Press ENTER or type command to continue}^ | + ]]} + + feed(':sign <tab>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {4: }{n: place }{4: }| + {6:fail} {n: undefine } | + {6:error}{n: unplace } | + :sign define^ | + ]]} + + feed('d') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + {6:fail} | + {6:error} | + :sign defined^ | + ]]} + end) + + it('wildoptions=pum and wildmode=longest,full #11622', function() + screen:try_resize(30,8) + command('set wildmenu') + command('set wildoptions=pum') + command('set wildmode=longest,full') + + -- With 'wildmode' set to 'longest,full', completing a match should display + -- the longest match, the wildmenu should not be displayed. + feed(':sign u<Tab>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign un^ | + ]]} + eq(0, funcs.wildmenumode()) + + -- pressing <Tab> should display the wildmenu + feed('<Tab>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign undefine^ | + ]]} + eq(1, funcs.wildmenumode()) + + -- pressing <Tab> second time should select the next entry in the menu + feed('<Tab>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]} + end) + + it('wildoptions=pum with a wrapped line in buffer vim-patch:8.2.4655', function() + screen:try_resize(32, 10) + meths.buf_set_lines(0, 0, -1, true, { ('a'):rep(100) }) + command('set wildoptions+=pum') + feed('$') + feed(':sign <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_odd_wildchar() + it('wildoptions=pum with odd wildchar', function() + screen:try_resize(30, 10) + -- Test odd wildchar interactions with pum. Make sure they behave properly + -- and don't lead to memory corruption due to improperly cleaned up memory. + exec([[ + set wildoptions=pum + set wildchar=<C-E> + ]]) + + feed(':sign <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^ | + ]]) + + -- <C-E> being a wildchar takes priority over its original functionality + feed('<C-E>') + 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('<Esc>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + + -- Escape key can be wildchar too. Double-<Esc> is hard-coded to escape + -- command-line, and we need to make sure to clean up properly. + command('set wildchar=<Esc>') + feed(':sign <Esc>') + 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>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + + -- <C-\> can also be wildchar. <C-\><C-N> however will still escape cmdline + -- and we again need to make sure we clean up properly. + command([[set wildchar=<C-\>]]) + feed([[:sign <C-\><C-\>]]) + 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-N>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) + 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 | - ]]) + it("'pumheight'", function() + screen:try_resize(32,8) + feed('isome long prefix before the ') + command("set completeopt+=noinsert,noselect") + command("set linebreak") + command("set pumheight=2") + funcs.complete(29, {'word', 'choice', 'text', 'thing'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + some long prefix before the ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- INSERT --} | + ## grid 4 + {n: word }{c: }| + {n: choice}{s: }| + ]], float_pos={ + [4] = {{id = -1}, "NW", 2, 1, 24, false, 100}; + }} + else + screen:expect([[ + some long prefix before the ^ | + {1:~ }{n: word }{c: }| + {1:~ }{n: choice}{s: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end + end) - -- go to the Paste entry in the menu - feed('jj') - screen:expect([[ - one two three four five | - and one two {7:^X}three four five | - one more tw{n: Undo } | - {1:~ }{n: }{1: }| - {1:~ }{s: Paste }{1: }| - {1:~ }{n: }{1: }| - {1:~ }{n: Select Word }{1: }| - {1:~ }{n: Select Sentence }{1: }| - {1:~ }{n: Select Paragraph }{1: }| - {1:~ }{n: Select Line }{1: }| - {1:~ }{n: Select Block }{1: }| - {1:~ }{n: Select All }{1: }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :popup PopUp | - ]]) + it("'pumwidth'", function() + screen:try_resize(32,8) + feed('isome long prefix before the ') + command("set completeopt+=noinsert,noselect") + command("set linebreak") + command("set pumwidth=8") + funcs.complete(29, {'word', 'choice', 'text', 'thing'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + some long prefix before the ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- INSERT --} | + ## grid 4 + {n: word }| + {n: choice}| + {n: text }| + {n: thing }| + ]], float_pos={ + [4] = {{id = -1}, "NW", 2, 1, 25, false, 100}; + }} + else + screen:expect([[ + some long prefix before the ^ | + {1:~ }{n: word }| + {1:~ }{n: choice}| + {1:~ }{n: text }| + {1:~ }{n: thing }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end + end) - -- 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 | - ]]) + it('does not crash when displayed in the last column with rightleft #12032', function() + local col = 30 + local items = {'word', 'choice', 'text', 'thing'} + local max_len = 0 + for _, v in ipairs(items) do + max_len = max_len < #v and #v or max_len + end + screen:try_resize(col, 8) + command('set rightleft') + command('call setline(1, repeat(" ", &columns - '..max_len..'))') + feed('$i') + funcs.complete(col - max_len, items) + feed('<c-y>') + assert_alive() + end) - feed('<Esc>') + it('truncates double-width character correctly without scrollbar', function() + screen:try_resize(32, 8) + command('set completeopt+=menuone,noselect') + feed('i' .. string.rep(' ', 13)) + funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'}) + if multigrid then + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- INSERT --} | + ## grid 4 + {n: 哦哦哦哦哦哦哦哦哦>}| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 12, false, 100}}}) + else + screen:expect([[ + ^ | + {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end + end) - -- 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 | - ]]) + it('truncates double-width character correctly with scrollbar', function() + screen:try_resize(32,8) + command('set completeopt+=noselect') + command('set pumheight=4') + feed('i' .. string.rep(' ', 12)) + local items = {} + for _ = 1, 8 do + table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1}) + end + funcs.complete(13, items) + if multigrid then + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- INSERT --} | + ## grid 4 + {n: 哦哦哦哦哦哦哦哦哦>}{c: }| + {n: 哦哦哦哦哦哦哦哦哦>}{c: }| + {n: 哦哦哦哦哦哦哦哦哦>}{s: }| + {n: 哦哦哦哦哦哦哦哦哦>}{s: }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}}) + else + screen:expect([[ + ^ | + {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{c: }| + {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{c: }| + {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{s: }| + {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{s: }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end + end) - -- 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) + it('supports mousemodel=popup', function() + screen:try_resize(32, 6) + exec([[ + call setline(1, 'popup menu test') + set mouse=a mousemodel=popup -describe('builtin popupmenu with ui/ext_multigrid', function() - local screen - before_each(function() - clear() - screen = Screen.new(32, 20) - screen:attach({ext_multigrid=true}) - screen:set_default_attr_ids({ - -- popup selected item / scrollbar track - ['s'] = {background = Screen.colors.WebGray}, - -- popup non-selected item - ['n'] = {background = Screen.colors.LightMagenta}, - -- popup scrollbar knob - ['c'] = {background = Screen.colors.Grey0}, - [1] = {bold = true, foreground = Screen.colors.Blue}, - [2] = {bold = true}, - [3] = {reverse = true}, - [4] = {bold = true, reverse = true}, - [5] = {bold = true, foreground = Screen.colors.SeaGreen}, - [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - }) - end) + 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> + ]]) - it('truncates double-width character correctly when there is no scrollbar', function() - screen:try_resize(32,8) - command('set completeopt+=menuone,noselect') - feed('i' .. string.rep(' ', 13)) - funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'}) - screen:expect({grid=[[ - ## grid 1 - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [3:--------------------------------]| - ## grid 2 - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - {2:-- INSERT --} | - ## grid 4 - {n: 哦哦哦哦哦哦哦哦哦>}| - ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 12, false, 100}}}) - end) + if multigrid then + meths.input_mouse('right', 'press', '', 2, 0, 4) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + {n: foo }| + {n: bar }| + {n: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}}) + else + feed('<RightMouse><4,0>') + screen:expect([[ + ^popup menu test | + {1:~ }{n: foo }{1: }| + {1:~ }{n: bar }{1: }| + {1:~ }{n: baz }{1: }| + {1:~ }| + | + ]]) + end + feed('<Down>') + if multigrid then + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + {s: foo }| + {n: bar }| + {n: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}}) + else + screen:expect([[ + ^popup menu test | + {1:~ }{s: foo }{1: }| + {1:~ }{n: bar }{1: }| + {1:~ }{n: baz }{1: }| + {1:~ }| + | + ]]) + end + feed('<Down>') + if multigrid then + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + {n: foo }| + {s: bar }| + {n: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}}) + else + screen:expect([[ + ^popup menu test | + {1:~ }{n: foo }{1: }| + {1:~ }{s: bar }{1: }| + {1:~ }{n: baz }{1: }| + {1:~ }| + | + ]]) + end + feed('<CR>') + if multigrid then + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'bar' | + ]]}) + else + screen:expect([[ + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :let g:menustr = 'bar' | + ]]) + end + eq('bar', meths.get_var('menustr')) + + if multigrid then + meths.input_mouse('right', 'press', '', 2, 2, 20) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'bar' | + ## grid 4 + {n: foo }| + {n: bar }| + {n: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 3, 19, false, 250}}}) + else + feed('<RightMouse><20,2>') + screen:expect([[ + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }{n: foo }{1: }| + {1:~ }{n: bar }{1: }| + :let g:menustr = 'b{n: baz } | + ]]) + end + if multigrid then + meths.input_mouse('left', 'press', '', 4, 2, 2) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'baz' | + ]]}) + else + feed('<LeftMouse><22,5>') + screen:expect([[ + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :let g:menustr = 'baz' | + ]]) + end + eq('baz', meths.get_var('menustr')) + + if multigrid then + meths.input_mouse('right', 'press', '', 2, 0, 4) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'baz' | + ## grid 4 + {n: foo }| + {n: bar }| + {n: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}}) + else + feed('<RightMouse><4,0>') + screen:expect([[ + ^popup menu test | + {1:~ }{n: foo }{1: }| + {1:~ }{n: bar }{1: }| + {1:~ }{n: baz }{1: }| + {1:~ }| + :let g:menustr = 'baz' | + ]]) + end + if multigrid then + meths.input_mouse('right', 'drag', '', 2, 3, 6) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'baz' | + ## grid 4 + {n: foo }| + {n: bar }| + {s: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}}) + else + feed('<RightDrag><6,3>') + screen:expect([[ + ^popup menu test | + {1:~ }{n: foo }{1: }| + {1:~ }{n: bar }{1: }| + {1:~ }{s: baz }{1: }| + {1:~ }| + :let g:menustr = 'baz' | + ]]) + end + if multigrid then + meths.input_mouse('right', 'release', '', 2, 1, 6) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'foo' | + ]]}) + else + feed('<RightRelease><6,1>') + screen:expect([[ + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :let g:menustr = 'foo' | + ]]) + end + eq('foo', meths.get_var('menustr')) + + eq(false, screen.options.mousemoveevent) + if multigrid then + meths.input_mouse('right', 'press', '', 2, 0, 4) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'foo' | + ## grid 4 + {n: foo }| + {n: bar }| + {n: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}}) + else + feed('<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' | + ]]) + end + eq(true, screen.options.mousemoveevent) + if multigrid then + meths.input_mouse('move', '', '', 2, 3, 6) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'foo' | + ## grid 4 + {n: foo }| + {n: bar }| + {s: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}}) + else + feed('<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' | + ]]) + end + eq(true, screen.options.mousemoveevent) + if multigrid then + meths.input_mouse('left', 'press', '', 2, 2, 6) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'bar' | + ]]}) + else + feed('<LeftMouse><6,2>') + screen:expect([[ + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :let g:menustr = 'bar' | + ]]) + end + eq(false, screen.options.mousemoveevent) + eq('bar', meths.get_var('menustr')) + + command('set laststatus=0 | botright split') + if multigrid then + meths.input_mouse('right', 'press', '', 5, 1, 20) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + {3:[No Name] [+] }| + [5:--------------------------------]| + [5:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + popup menu test | + {1:~ }| + ## grid 3 + :let g:menustr = 'bar' | + ## grid 4 + {n: foo }| + {n: bar }| + {n: baz }| + ## grid 5 + ^popup menu test | + {1:~ }| + ]], float_pos={[4] = {{id = -1}, "SW", 5, 1, 19, false, 250}}}) + else + feed('<RightMouse><20,4>') + screen:expect([[ + popup menu test | + {1:~ }{n: foo }{1: }| + {3:[No Name] [+] }{n: bar }{3: }| + ^popup menu test {n: baz } | + {1:~ }| + :let g:menustr = 'bar' | + ]]) + end + if multigrid then + meths.input_mouse('left', 'press', '', 4, 2, 2) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + {3:[No Name] [+] }| + [5:--------------------------------]| + [5:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + popup menu test | + {1:~ }| + ## grid 3 + :let g:menustr = 'baz' | + ## grid 5 + ^popup menu test | + {1:~ }| + ]]}) + else + feed('<LeftMouse><22,3>') + screen:expect([[ + popup menu test | + {1:~ }| + {3:[No Name] [+] }| + ^popup menu test | + {1:~ }| + :let g:menustr = 'baz' | + ]]) + end + eq('baz', meths.get_var('menustr')) + + command('set winwidth=1 | rightbelow vsplit') + if multigrid then + meths.input_mouse('right', 'press', '', 6, 1, 14) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + {3:[No Name] [+] }| + [5:---------------]│[6:----------------]| + [5:---------------]│[6:----------------]| + [3:--------------------------------]| + ## grid 2 + popup menu test | + {1:~ }| + ## grid 3 + :let g:menustr = 'baz' | + ## grid 4 + {n: foo}| + {n: bar}| + {n: baz}| + ## grid 5 + popup menu test| + {1:~ }| + ## grid 6 + ^popup menu test | + {1:~ }| + ]], float_pos={[4] = {{id = -1}, "SW", 6, 1, 12, false, 250}}}) + else + feed('<RightMouse><30,4>') + screen:expect([[ + popup menu test | + {1:~ }{n: foo}| + {3:[No Name] [+] }{n: bar}| + popup menu test│^popup menu t{n: baz}| + {1:~ }│{1:~ }| + :let g:menustr = 'baz' | + ]]) + end + if multigrid then + meths.input_mouse('left', 'press', '', 4, 0, 2) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + {3:[No Name] [+] }| + [5:---------------]│[6:----------------]| + [5:---------------]│[6:----------------]| + [3:--------------------------------]| + ## grid 2 + popup menu test | + {1:~ }| + ## grid 3 + :let g:menustr = 'foo' | + ## grid 5 + popup menu test| + {1:~ }| + ## grid 6 + ^popup menu test | + {1:~ }| + ]]}) + else + feed('<LeftMouse><31,1>') + screen:expect([[ + popup menu test | + {1:~ }| + {3:[No Name] [+] }| + popup menu test│^popup menu test | + {1:~ }│{1:~ }| + :let g:menustr = 'foo' | + ]]) + end + eq('foo', meths.get_var('menustr')) + + command('setlocal winbar=WINBAR') + if multigrid then + meths.input_mouse('right', 'press', '', 6, 1, 14) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + {3:[No Name] [+] }| + [5:---------------]│[6:----------------]| + [5:---------------]│[6:----------------]| + [3:--------------------------------]| + ## grid 2 + popup menu test | + {1:~ }| + ## grid 3 + :let g:menustr = 'foo' | + ## grid 4 + {n: foo}| + {n: bar}| + {n: baz}| + ## grid 5 + popup menu test| + {1:~ }| + ## grid 6 + {2:WINBAR }| + ^popup menu test | + ]], float_pos={[4] = {{id = -1}, "SW", 6, 1, 12, false, 250}}}) + else + feed('<RightMouse><30,4>') + screen:expect([[ + popup menu test | + {1:~ }{n: foo}| + {3:[No Name] [+] }{n: bar}| + popup menu test│{2:WINBAR }{n: baz}| + {1:~ }│^popup menu test | + :let g:menustr = 'foo' | + ]]) + end + if multigrid then + meths.input_mouse('left', 'press', '', 4, 1, 2) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + {3:[No Name] [+] }| + [5:---------------]│[6:----------------]| + [5:---------------]│[6:----------------]| + [3:--------------------------------]| + ## grid 2 + popup menu test | + {1:~ }| + ## grid 3 + :let g:menustr = 'bar' | + ## grid 5 + popup menu test| + {1:~ }| + ## grid 6 + {2:WINBAR }| + ^popup menu test | + ]]}) + else + feed('<LeftMouse><31,2>') + screen:expect([[ + popup menu test | + {1:~ }| + {3:[No Name] [+] }| + popup menu test│{2:WINBAR }| + {1:~ }│^popup menu test | + :let g:menustr = 'bar' | + ]]) + end + eq('bar', meths.get_var('menustr')) + end) - it('truncates double-width character correctly when there is scrollbar', function() - screen:try_resize(32,8) - command('set completeopt+=noselect') - command('set pumheight=4') - feed('i' .. string.rep(' ', 12)) - local items = {} - for _ = 1, 8 do - table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1}) + if not multigrid then + -- oldtest: Test_popup_command_dump() + it(':popup command', function() + exec([[ + func ChangeMenu() + aunmenu PopUp.&Paste + nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<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 | + ]]) + + -- Add a window toolbar to the window and check the :popup menu position. + command('setlocal winbar=TEST') + feed('/X<CR>:popup PopUp<CR>') + screen:expect([[ + {2:TEST }| + one two three four five | + and one two {7:^X}three four five | + one more tw{n: Undo } | + {1:~ }{n: }{1: }| + {1:~ }{n: Paste }{1: }| + {1:~ }{n: }{1: }| + {1:~ }{n: Select Word }{1: }| + {1:~ }{n: Select Sentence }{1: }| + {1:~ }{n: Select Paragraph }{1: }| + {1:~ }{n: Select Line }{1: }| + {1:~ }{n: Select Block }{1: }| + {1:~ }{n: Select All }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :popup PopUp | + ]]) + + feed('<Esc>') + end) + + describe('"kind" and "menu"', function() + before_each(function() + screen:try_resize(30, 8) + exec([[ + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, + \ { 'word': 'aword3', 'menu': 'extra text 3', 'kind': 'W', }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + ]]) + end) + + -- oldtest: Test_pum_highlights_default() + it('default highlight groups', function() + feed('iaw<C-X><C-u>') + screen:expect([[ + aword1^ | + {s:aword1 W extra text 1 }{1: }| + {n:aword2 W extra text 2 }{1: }| + {n:aword3 W extra text 3 }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]]) + end) + + -- oldtest: Test_pum_highlights_custom() + it('custom highlight groups', function() + exec([[ + hi PmenuKind guifg=Red guibg=Magenta + hi PmenuKindSel guifg=Red guibg=Grey + hi PmenuExtra guifg=White guibg=Magenta + hi PmenuExtraSel guifg=Black guibg=Grey + ]]) + local attrs = screen:get_default_attr_ids() + attrs.kn = {foreground = Screen.colors.Red, background = Screen.colors.Magenta} + attrs.ks = {foreground = Screen.colors.Red, background = Screen.colors.Grey} + attrs.xn = {foreground = Screen.colors.White, background = Screen.colors.Magenta} + attrs.xs = {foreground = Screen.colors.Black, background = Screen.colors.Grey} + feed('iaw<C-X><C-u>') + screen:expect([[ + aword1^ | + {s:aword1 }{ks:W }{xs:extra text 1 }{1: }| + {n:aword2 }{kn:W }{xn:extra text 2 }{1: }| + {n:aword3 }{kn:W }{xn:extra text 3 }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]], attrs) + end) + end) end - funcs.complete(13, items) - screen:expect({grid=[[ - ## grid 1 - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [3:--------------------------------]| - ## grid 2 - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - {2:-- INSERT --} | - ## grid 4 - {n: 哦哦哦哦哦哦哦哦哦>}{c: }| - {n: 哦哦哦哦哦哦哦哦哦>}{c: }| - {n: 哦哦哦哦哦哦哦哦哦>}{s: }| - {n: 哦哦哦哦哦哦哦哦哦>}{s: }| - ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}}) - end) + end - it('supports mousemodel=popup', function() - screen:try_resize(32, 6) - exec([[ - call setline(1, 'popup menu test') - set mouse=a mousemodel=popup + describe('with ext_multigrid', function() + with_ext_multigrid(true) + end) - aunmenu PopUp - menu PopUp.foo :let g:menustr = 'foo'<CR> - menu PopUp.bar :let g:menustr = 'bar'<CR> - menu PopUp.baz :let g:menustr = 'baz'<CR> - ]]) - meths.input_mouse('right', 'press', '', 2, 1, 20) - screen:expect({grid=[[ - ## grid 1 - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [3:--------------------------------]| - ## grid 2 - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - | - ## grid 4 - {n: foo }| - {n: bar }| - {n: baz }| - ]], float_pos={[4] = {{id = -1}, 'NW', 2, 2, 19, false, 100}}}) - meths.input_mouse('left', 'press', '', 4, 2, 2) - screen:expect({grid=[[ - ## grid 1 - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [3:--------------------------------]| - ## grid 2 - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - :let g:menustr = 'baz' | - ]]}) - eq('baz', meths.get_var('menustr')) - meths.input_mouse('right', 'press', '', 2, 0, 4) - screen:expect({grid=[[ - ## grid 1 - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [3:--------------------------------]| - ## grid 2 - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - :let g:menustr = 'baz' | - ## grid 4 - {n: foo }| - {n: bar }| - {n: baz }| - ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}}) - meths.input_mouse('right', 'drag', '', 2, 3, 6) - screen:expect({grid=[[ - ## grid 1 - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [3:--------------------------------]| - ## grid 2 - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - :let g:menustr = 'baz' | - ## grid 4 - {n: foo }| - {n: bar }| - {s: baz }| - ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}}) - meths.input_mouse('right', 'release', '', 2, 1, 6) - screen:expect({grid=[[ - ## grid 1 - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [3:--------------------------------]| - ## grid 2 - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - :let g:menustr = 'foo' | - ]]}) - eq('foo', meths.get_var('menustr')) - eq(false, screen.options.mousemoveevent) - meths.input_mouse('right', 'press', '', 2, 0, 4) - screen:expect({grid=[[ - ## grid 1 - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [2:--------------------------------]| - [3:--------------------------------]| - ## grid 2 - ^popup menu test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - :let g:menustr = 'foo' | - ## grid 4 - {n: foo }| - {n: bar }| - {n: baz }| - ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 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')) + describe('without ext_multigrid', function() + with_ext_multigrid(false) end) end) diff --git a/test/functional/ui/quickfix_spec.lua b/test/functional/ui/quickfix_spec.lua index b0d89ee3b6..df43871e60 100644 --- a/test/functional/ui/quickfix_spec.lua +++ b/test/functional/ui/quickfix_spec.lua @@ -27,7 +27,7 @@ describe('quickfix selection highlight', function() [12] = {foreground = Screen.colors.Brown, background = Screen.colors.Fuchsia}, }) - meths.set_option('errorformat', '%m %l') + meths.set_option_value('errorformat', '%m %l', {}) command('syntax on') command('highlight Search guibg=Green') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 3b9cce0e6f..810a68d387 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -75,6 +75,7 @@ local busted = require('busted') local deepcopy = helpers.deepcopy local shallowcopy = helpers.shallowcopy local concat_tables = helpers.concat_tables +local pesc = helpers.pesc local run_session = helpers.run_session local eq = helpers.eq local dedent = helpers.dedent @@ -87,6 +88,7 @@ local function isempty(v) return type(v) == 'table' and next(v) == nil end +--- @class test.functional.ui.screen local Screen = {} Screen.__index = Screen @@ -149,6 +151,7 @@ function Screen.new(width, height) msg_grid = nil, msg_grid_pos = nil, _session = nil, + rpc_async = false, messages = {}, msg_history = {}, showmode = {}, @@ -172,9 +175,13 @@ function Screen.new(width, height) _busy = false, }, Screen) local function ui(method, ...) - local status, rv = self._session:request('nvim_ui_'..method, ...) - if not status then - error(rv[2]) + if self.rpc_async then + self._session:notify('nvim_ui_'..method, ...) + else + local status, rv = self._session:request('nvim_ui_'..method, ...) + if not status then + error(rv[2]) + end end end self.uimeths = create_callindex(ui) @@ -214,7 +221,7 @@ function Screen:attach(options, session) -- simplify test code by doing the same. self._options.rgb = true end - if self._options.ext_multigrid or self._options.ext_float then + if self._options.ext_multigrid then self._options.ext_linegrid = true end end @@ -257,7 +264,7 @@ local ext_keys = { -- grid: Expected screen state (string). Each line represents a screen -- row. Last character of each row (typically "|") is stripped. -- Common indentation is stripped. --- "{MATCH:x}|" lines are matched against Lua pattern `x`. +-- "{MATCH:x}" in a line is matched against Lua pattern `x`. -- attr_ids: Expected text attributes. Screen rows are transformed according -- to this table, as follows: each substring S composed of -- characters having the same attributes will be substituted by @@ -382,8 +389,20 @@ function Screen:expect(expected, attr_ids, ...) end for i, row in ipairs(expected_rows) do msg_expected_rows[i] = row - local m = (row ~= actual_rows[i] and row:match('{MATCH:(.*)}') or nil) - if row ~= actual_rows[i] and (not m or not (actual_rows[i] and actual_rows[i]:match(m))) then + local pat = nil + if actual_rows[i] and row ~= actual_rows[i] then + local after = row + while true do + local s, e, m = after:find('{MATCH:(.-)}') + if not s then + pat = pat and (pat .. pesc(after)) + break + end + pat = (pat or '') .. pesc(after:sub(1, s - 1)) .. m + after = after:sub(e + 1) + end + end + if row ~= actual_rows[i] and (not pat or not actual_rows[i]:match(pat)) then msg_expected_rows[i] = '*' .. msg_expected_rows[i] if i <= #actual_rows then actual_rows[i] = '*' .. actual_rows[i] @@ -470,15 +489,19 @@ screen:redraw_debug() to show all intermediate screen states. ]]) end, expected) end -function Screen:expect_unchanged(waittime_ms, ignore_attrs, request_cb) +function Screen:expect_unchanged(intermediate, waittime_ms, ignore_attrs) waittime_ms = waittime_ms and waittime_ms or 100 -- Collect the current screen state. - self:sleep(0, request_cb) local kwargs = self:get_snapshot(nil, ignore_attrs) - -- Check that screen state does not change. - kwargs.unchanged = true + if intermediate then + kwargs.intermediate = true + else + kwargs.unchanged = true + end + kwargs.timeout = waittime_ms + -- Check that screen state does not change. self:expect(kwargs) end @@ -540,6 +563,7 @@ function Screen:_wait(check, flags) self._session:stop() end elseif success_seen and #args > 0 then + success_seen = false failure_after_success = true -- print(inspect(args)) end @@ -785,14 +809,17 @@ function Screen:_handle_win_pos(grid, win, startrow, startcol, width, height) self.float_pos[grid] = nil end -function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol, linecount) +function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol, linecount, scroll_delta) + -- accumulate scroll delta + local last_scroll_delta = self.win_viewport[grid] and self.win_viewport[grid].sum_scroll_delta or 0 self.win_viewport[grid] = { win = win, topline = topline, botline = botline, curline = curline, curcol = curcol, - linecount = linecount + linecount = linecount, + sum_scroll_delta = scroll_delta + last_scroll_delta } end @@ -926,6 +953,7 @@ end function Screen:_handle_grid_line(grid, row, col, items) assert(self._options.ext_linegrid) + assert(#items > 0) local line = self._grids[grid].rows[row+1] local colpos = col+1 local hl_id = 0 @@ -1248,7 +1276,7 @@ end function Screen:render(headers, attr_state, preview) headers = headers and (self._options.ext_multigrid or self._options._debug_float) local rv = {} - for igrid,grid in pairs(self._grids) do + for igrid,grid in vim.spairs(self._grids) do if headers then local suffix = "" if igrid > 1 and self.win_position[igrid] == nil @@ -1330,7 +1358,7 @@ local function fmt_ext_state(name, state) for k,v in pairs(state) do str = (str.." ["..k.."] = {win = {id = "..v.win.id.."}, topline = " ..v.topline..", botline = "..v.botline..", curline = "..v.curline - ..", curcol = "..v.curcol..", linecount = "..v.linecount.."};\n") + ..", curcol = "..v.curcol..", linecount = "..v.linecount..", sum_scroll_delta = "..v.sum_scroll_delta.."};\n") end return str .. "}" elseif name == "float_pos" then diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 3bd2289a73..7cc1accd3f 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -4,9 +4,7 @@ local spawn, set_session, clear = helpers.spawn, helpers.set_session, helpers.cl local feed, command = helpers.feed, helpers.command local insert = helpers.insert local eq = helpers.eq -local eval = helpers.eval -local funcs, meths, exec_lua = helpers.funcs, helpers.meths, helpers.exec_lua -local is_os = helpers.is_os +local funcs, meths = helpers.funcs, helpers.meths describe('screen', function() local screen @@ -61,37 +59,10 @@ local function screen_tests(linegrid) [5] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Fuchsia}, [6] = {bold = true, foreground = Screen.colors.Fuchsia}, [7] = {bold = true, foreground = Screen.colors.SeaGreen}, + [8] = {foreground = Screen.colors.White, background = Screen.colors.Red}, } ) end) - describe(':suspend', function() - it('is forwarded to the UI', function() - local function check() - eq(true, screen.suspended) - end - - command('let g:ev = []') - command('autocmd VimResume * :call add(g:ev, "r")') - command('autocmd VimSuspend * :call add(g:ev, "s")') - - eq(false, screen.suspended) - command('suspend') - eq({ 's', 'r' }, eval('g:ev')) - - screen:expect(check) - screen.suspended = false - - feed('<c-z>') - eq({ 's', 'r', 's', 'r' }, eval('g:ev')) - - screen:expect(check) - screen.suspended = false - - command('suspend') - eq({ 's', 'r', 's', 'r', 's', 'r' }, eval('g:ev')) - end) - end) - describe('bell/visual bell', function() it('is forwarded to the UI', function() feed('<left>') @@ -117,78 +88,13 @@ local function screen_tests(linegrid) screen:expect(function() eq(expected, screen.title) end) - end) - - it('has correct default title with unnamed file', function() - local expected = '[No Name] - NVIM' - command('set title') - screen:expect(function() - eq(expected, screen.title) - end) - end) - - it('has correct default title with named file', function() - local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM') - command('set title') - command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile') + screen:detach() + screen.title = nil + screen:attach() screen:expect(function() eq(expected, screen.title) end) end) - - describe('is not changed by', function() - local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1' - local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2' - local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM') - local buf2 - - before_each(function() - command('edit '..file1) - buf2 = funcs.bufadd(file2) - command('set title') - end) - - it('calling setbufvar() to set an option in a hidden buffer from i_CTRL-R', function() - command([[inoremap <F2> <C-R>=setbufvar(]]..buf2..[[, '&autoindent', 1) ? '' : ''<CR>]]) - feed('i<F2><Esc>') - command('redraw!') - screen:expect(function() - eq(expected, screen.title) - end) - end) - - it('an RPC call to nvim_buf_set_option in a hidden buffer', function() - meths.buf_set_option(buf2, 'autoindent', true) - command('redraw!') - screen:expect(function() - eq(expected, screen.title) - end) - end) - - it('a Lua callback calling nvim_buf_set_option in a hidden buffer', function() - exec_lua(string.format([[ - vim.schedule(function() - vim.api.nvim_buf_set_option(%d, 'autoindent', true) - end) - ]], buf2)) - command('redraw!') - screen:expect(function() - eq(expected, screen.title) - end) - end) - - it('a Lua callback calling nvim_buf_call in a hidden buffer', function() - exec_lua(string.format([[ - vim.schedule(function() - vim.api.nvim_buf_call(%d, function() end) - end) - ]], buf2)) - command('redraw!') - screen:expect(function() - eq(expected, screen.title) - end) - end) - end) end) describe(':set icon', function() @@ -199,6 +105,12 @@ local function screen_tests(linegrid) screen:expect(function() eq(expected, screen.icon) end) + screen:detach() + screen.icon = nil + screen:attach() + screen:expect(function() + eq(expected, screen.icon) + end) end) end) @@ -866,12 +778,9 @@ local function screen_tests(linegrid) end) describe('resize', function() - before_each(function() + it('rebuilds the whole screen', function() screen:try_resize(25, 5) feed('iresize') - end) - - it('rebuilds the whole screen', function() screen:expect([[ resize^ | {0:~ }| @@ -882,10 +791,11 @@ local function screen_tests(linegrid) end) it('has minimum width/height values', function() + feed('iresize') screen:try_resize(1, 1) screen:expect([[ resize^ | - {2:-- INSERT -} | + {2:-- INSERT --}| ]]) feed('<esc>:ls') @@ -896,11 +806,12 @@ local function screen_tests(linegrid) end) it('VimResized autocommand does not cause invalid UI events #20692 #20759', function() - feed('<Esc>') + screen:try_resize(25, 5) + feed('iresize<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) + meths.set_option_value('showtabline', 2, {}) screen:expect([[ {2: + [No Name] }{3: }| resiz^e | @@ -919,6 +830,77 @@ local function screen_tests(linegrid) ]]) eq(29, meths.get_var('echospace')) end) + + it('messages from the same Ex command as resize are visible #22225', function() + feed(':set columns=20 | call<CR>') + screen:expect([[ + | + | + | + | + | + | + | + | + | + {1: }| + {8:E471: Argument requi}| + {8:red} | + {7:Press ENTER or type }| + {7:command to continue}^ | + ]]) + feed('<CR>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed(':set columns=0<CR>') + screen:expect([[ + | + | + | + | + | + {1: }| + {8:E594: Need a}| + {8:t least 12 c}| + {8:olumns: colu}| + {8:mns=0} | + {7:Press ENTER }| + {7:or type comm}| + {7:and to conti}| + {7:nue}^ | + ]]) + feed('<CR>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) end) describe('press enter', function() @@ -1057,8 +1039,8 @@ it('CTRL-F or CTRL-B scrolls a page after UI attach/resize #20605', function() clear() local screen = Screen.new(100, 100) screen:attach() - eq(100, meths.get_option('lines')) - eq(99, meths.get_option('window')) + eq(100, meths.get_option_value('lines', {})) + eq(99, meths.get_option_value('window', {})) eq(99, meths.win_get_height(0)) feed('1000o<Esc>') eq(903, funcs.line('w0')) @@ -1072,8 +1054,8 @@ it('CTRL-F or CTRL-B scrolls a page after UI attach/resize #20605', function() eq(903, funcs.line('w0')) feed('G') screen:try_resize(50, 50) - eq(50, meths.get_option('lines')) - eq(49, meths.get_option('window')) + eq(50, meths.get_option_value('lines', {})) + eq(49, meths.get_option_value('window', {})) eq(49, meths.win_get_height(0)) eq(953, funcs.line('w0')) feed('<C-B>') @@ -1085,3 +1067,18 @@ it('CTRL-F or CTRL-B scrolls a page after UI attach/resize #20605', function() feed('<C-F>') eq(953, funcs.line('w0')) end) + +it("showcmd doesn't cause empty grid_line with redrawdebug=compositor #22593", function() + clear() + local screen = Screen.new(30, 2) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + }) + screen:attach() + command('set showcmd redrawdebug=compositor') + feed('d') + screen:expect{grid=[[ + ^ | + d | + ]]} +end) diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 18bbb56a61..dc7ef666bd 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -10,7 +10,6 @@ local testprg = helpers.testprg describe('search highlighting', function() local screen - local colors = Screen.colors before_each(function() clear() @@ -18,9 +17,10 @@ describe('search highlighting', function() screen:attach() screen:set_default_attr_ids( { [1] = {bold=true, foreground=Screen.colors.Blue}, - [2] = {background = colors.Yellow}, -- Search + [2] = {background = Screen.colors.Yellow}, -- Search [3] = {reverse = true}, - [4] = {foreground = colors.Red}, -- Message + [4] = {foreground = Screen.colors.Red}, -- WarningMsg + [5] = {bold = true, reverse = true}, -- StatusLine [6] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey}, -- Folded }) end) @@ -53,11 +53,11 @@ describe('search highlighting', function() {1:~ }| /text^ | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 9, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 8, linecount = 2, sum_scroll_delta = 0}; }} end) - it('works', function() + local function test_search_hl() insert([[ some text more textstuff @@ -110,6 +110,26 @@ describe('search highlighting', function() {1:~ }| :nohlsearch | ]]) + end + + it("works when 'winhighlight' is not set", function() + test_search_hl() + end) + + it("works when 'winhighlight' doesn't change Search highlight", function() + command('setlocal winhl=NonText:Underlined') + local attrs = screen:get_default_attr_ids() + attrs[1] = {foreground = Screen.colors.SlateBlue, underline = true} + screen:set_default_attr_ids(attrs) + test_search_hl() + end) + + it("works when 'winhighlight' changes Search highlight", function() + command('setlocal winhl=Search:Underlined') + local attrs = screen:get_default_attr_ids() + attrs[2] = {foreground = Screen.colors.SlateBlue, underline = true} + screen:set_default_attr_ids(attrs) + test_search_hl() end) describe('CurSearch highlight', function() @@ -307,18 +327,33 @@ describe('search highlighting', function() it('is preserved during :terminal activity', function() feed((':terminal "%s" REP 5000 foo<cr>'):format(testprg('shell-test'))) - feed(':file term<CR>') + screen:expect([[ + ^0: foo | + 1: foo | + 2: foo | + 3: foo | + 4: foo | + 5: foo | + :file term | + ]]) + feed('G') -- Follow :terminal output. feed(':vnew<CR>') insert([[ foo bar baz bar baz foo - bar foo baz - ]]) + bar foo baz]]) feed('/foo') - helpers.poke_eventloop() - screen:expect_unchanged() + screen:expect([[ + {3:foo} bar baz │{MATCH:%d+}: {2:foo}{MATCH:%s+}| + bar baz {2:foo} │{MATCH:%d+}: {2:foo}{MATCH:%s+}| + bar {2:foo} baz │{MATCH:%d+}: {2:foo}{MATCH:%s+}| + {1:~ }│{MATCH:.*}| + {1:~ }│{MATCH:.*}| + {5:[No Name] [+] }{3:term }| + /foo^ | + ]]) end) it('works with incsearch', function() @@ -498,6 +533,50 @@ describe('search highlighting', function() {1:~ }│{1:~ }| //^ | ]]) + feed('<Esc>') + + -- incsearch works after c_CTRL-R_CTRL-R + command('let @" = "file"') + feed('/<C-R><C-R>"') + screen:expect([[ + the first line │the first line | + in a little {3:file} │in a little {2:file} | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + /file^ | + ]]) + feed('<Esc>') + + command('set rtp^=test/functional/fixtures') + -- incsearch works after c_CTRL-R inserts clipboard register + + command('let @* = "first"') + feed('/<C-R>*') + screen:expect([[ + the {3:first} line │the {2:first} line | + in a little file │in a little file | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + /first^ | + ]]) + feed('<Esc>') + + command('let @+ = "little"') + feed('/<C-R>+') + screen:expect([[ + the first line │the first line | + in a {3:little} file │in a {2:little} file | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + /little^ | + ]]) + feed('<Esc>') end) it('works with incsearch and offset', function() @@ -572,12 +651,12 @@ describe('search highlighting', function() it('works with matchadd and syntax', function() screen:set_default_attr_ids { [1] = {bold=true, foreground=Screen.colors.Blue}; - [2] = {background = colors.Yellow}; + [2] = {background = Screen.colors.Yellow}; [3] = {reverse = true}; - [4] = {foreground = colors.Red}; - [5] = {bold = true, background = colors.Green}; - [6] = {italic = true, background = colors.Magenta}; - [7] = {bold = true, background = colors.Yellow}; + [4] = {foreground = Screen.colors.Red}; + [5] = {bold = true, background = Screen.colors.Green}; + [6] = {italic = true, background = Screen.colors.Magenta}; + [7] = {bold = true, background = Screen.colors.Yellow}; [8] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGray}; } feed_command('set hlsearch') @@ -602,7 +681,7 @@ describe('search highlighting', function() {1:~ }| {4:search hit BOTTOM, continuing at TOP} | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 11, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 11, linecount = 2, sum_scroll_delta = 0}; }} -- check highlights work also in folds diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index 7dcd4cff25..b12e79bd42 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -274,9 +274,9 @@ describe('Signs', function() -- Line 3 checks that with a limit over the maximum number -- of signs, the ones with the highest Ids are being picked, -- and presented by their sorted Id order. - command('sign place 4 line=3 name=pietSearch buffer=1') - command('sign place 5 line=3 name=pietWarn buffer=1') - command('sign place 3 line=3 name=pietError buffer=1') + command('sign place 6 line=3 name=pietSearch buffer=1') + command('sign place 7 line=3 name=pietWarn buffer=1') + command('sign place 5 line=3 name=pietError buffer=1') screen:expect([[ {1:>>}{8:XX}{6: 1 }a | {8:XX}{1:>>}{6: 2 }b | @@ -467,6 +467,27 @@ describe('Signs', function() {0:~ }| | ]]) + -- should not increase size because sign with existing id is moved + command('sign place 4 line=1 name=pietSearch buffer=1') + screen:expect_unchanged() + command('sign unplace 4') + screen:expect([[ + {1:>>>>>>}{6: 1 }a | + {2: }{6: 2 }b | + {2: }{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + command('sign place 4 line=1 name=pietSearch buffer=1') -- should keep the column at maximum size when signs are -- exceeding the maximum command('sign place 5 line=1 name=pietSearch buffer=1') @@ -685,4 +706,21 @@ describe('Signs', function() | ]]) end) + + it('numhl highlight is applied when signcolumn=no', function() + screen:try_resize(screen._width, 4) + command([[ + set nu scl=no + call setline(1, ['line1', 'line2', 'line3']) + call nvim_buf_set_extmark(0, nvim_create_namespace('test'), 0, 0, {'number_hl_group':'Error'}) + call sign_define('foo', { 'text':'F', 'numhl':'Error' }) + call sign_place(0, '', 'foo', bufnr(''), { 'lnum':2 }) + ]]) + screen:expect([[ + {8: 1 }^line1 | + {8: 2 }line2 | + {6: 3 }line3 | + | + ]]) + end) end) diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua index 361f83d1ce..d18e19e5b2 100644 --- a/test/functional/ui/spell_spec.lua +++ b/test/functional/ui/spell_spec.lua @@ -3,9 +3,11 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear = helpers.clear +local exec = helpers.exec local feed = helpers.feed local insert = helpers.insert -local command = helpers.command +local meths = helpers.meths +local curbufmeths = helpers.curbufmeths local is_os = helpers.is_os describe("'spell'", function() @@ -18,17 +20,21 @@ describe("'spell'", function() screen:set_default_attr_ids( { [0] = {bold=true, foreground=Screen.colors.Blue}, [1] = {special = Screen.colors.Red, undercurl = true}, - [2] = {special = Screen.colors.Blue1, undercurl = true}, + [2] = {special = Screen.colors.Blue, undercurl = true}, [3] = {foreground = tonumber('0x6a0dad')}, [4] = {foreground = Screen.colors.Magenta}, [5] = {bold = true, foreground = Screen.colors.SeaGreen}, [6] = {foreground = Screen.colors.Red}, + [7] = {foreground = Screen.colors.Blue}, + [8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true}, + [9] = {bold = true}, + [10] = {background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue}, }) end) it('joins long lines #7937', function() if is_os('openbsd') then pending('FIXME #12104', function() end) return end - command('set spell') + exec('set spell') insert([[ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, @@ -53,114 +59,374 @@ describe("'spell'", function() -- oldtest: Test_spell_screendump() it('has correct highlight at start of line', function() - insert([[ - "This is some text without any spell errors. Everything", - "should just be black, nothing wrong here.", - "", - "This line has a sepll error. and missing caps.", - "And and this is the the duplication.", - "with missing caps here.", - ]]) - command('set spell spelllang=en_nz') - screen:expect([[ - "This is some text without any spell errors. Everything", | - "should just be black, nothing wrong here.", | - "", | - "This line has a {1:sepll} error. {2:and} missing caps.", | - "{1:And and} this is {1:the the} duplication.", | - "with missing caps here.", | - ^ | - | + exec([=[ + call setline(1, [ + \"This is some text without any spell errors. Everything", + \"should just be black, nothing wrong here.", + \"", + \"This line has a sepll error. and missing caps.", + \"And and this is the the duplication.", + \"with missing caps here.", + \]) + set spell spelllang=en_nz + ]=]) + screen:expect([[ + ^This is some text without any spell errors. Everything | + should just be black, nothing wrong here. | + | + This line has a {1:sepll} error. {2:and} missing caps. | + {1:And and} this is {1:the the} duplication. | + {2:with} missing caps here. | + {0:~ }| + | ]]) end) - it('"noplainbuffer" and syntax #20385', function() - command('set filetype=c') - command('syntax on') - command('set spell') + -- oldtest: Test_spell_screendump_spellcap() + it('SpellCap highlight at start of line', function() + exec([=[ + call setline(1, [ + \" This line has a sepll error. and missing caps and trailing spaces. ", + \"another missing cap here.", + \"", + \"and here.", + \" ", + \"and here." + \]) + set spell spelllang=en + ]=]) + screen:expect([[ + ^ This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. | + {2:another} missing cap here. | + | + {2:and} here. | + | + {2:and} here. | + {0:~ }| + | + ]]) + -- After adding word missing Cap in next line is updated + feed('3GANot<Esc>') + screen:expect([[ + This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. | + {2:another} missing cap here. | + No^t | + and here. | + | + {2:and} here. | + {0:~ }| + | + ]]) + -- Deleting a full stop removes missing Cap in next line + feed('5Gdd<C-L>k$x') + screen:expect([[ + This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. | + {2:another} missing cap here. | + Not | + and her^e | + and here. | + {0:~ }| + {0:~ }| + | + ]]) + -- Undo also updates the next line (go to command line to remove message) + feed('u:<Esc>') + screen:expect([[ + This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. | + {2:another} missing cap here. | + Not | + and here^. | + {2:and} here. | + {0:~ }| + {0:~ }| + | + ]]) + -- Folding an empty line does not remove Cap in next line + feed('uzfk:<Esc>') + screen:expect([[ + This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. | + {2:another} missing cap here. | + Not | + {10:^+-- 2 lines: and here.·························································}| + {2:and} here. | + {0:~ }| + {0:~ }| + | + ]]) + -- Folding the end of a sentence does not remove Cap in next line + -- and editing a line does not remove Cap in current line + feed('Jzfkk$x') + screen:expect([[ + This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. | + {2:another} missing cap her^e | + {10:+-- 2 lines: Not·······························································}| + {2:and} here. | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- Cap is correctly applied in the first row of a window + feed('<C-E><C-L>') + screen:expect([[ + {2:another} missing cap her^e | + {10:+-- 2 lines: Not·······························································}| + {2:and} here. | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- Adding an empty line does not remove Cap in "mod_bot" area + feed('zbO<Esc>') + screen:expect([[ + This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. | + ^ | + {2:another} missing cap here | + {10:+-- 2 lines: Not·······························································}| + {2:and} here. | + {0:~ }| + {0:~ }| + | + ]]) + -- Multiple empty lines does not remove Cap in the line after + feed('O<Esc><C-L>') + screen:expect([[ + This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. | + ^ | + | + {2:another} missing cap here | + {10:+-- 2 lines: Not·······························································}| + {2:and} here. | + {0:~ }| + | + ]]) + end) + + -- oldtest: Test_spell_compatible() + it([[redraws properly when using "C" and "$" is in 'cpo']], function() + exec([=[ + call setline(1, [ + \ "test "->repeat(20), + \ "", + \ "end", + \ ]) + set spell cpo+=$ + ]=]) + feed('51|C') + screen:expect([[ + {2:test} test test test test test test test test test ^test test test test test test | + test test test test$ | + | + {2:end} | + {0:~ }| + {0:~ }| + {0:~ }| + {9:-- INSERT --} | + ]]) + feed('x') + screen:expect([[ + {2:test} test test test test test test test test test x^est test test test test test | + test test test test$ | + | + {2:end} | + {0:~ }| + {0:~ }| + {0:~ }| + {9:-- INSERT --} | + ]]) + end) + + it('extmarks, "noplainbuffer" and syntax #20385 #23398', function() + exec('set filetype=c') + exec('syntax on') + exec('set spell') insert([[ #include <stdbool.h> - bool func(void);]]) + bool func(void); + // I am a speling mistakke]]) + feed('ge') + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} func({5:void}); | + {7:// I am a }{8:spelin^g}{7: }{8:mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed(']s') + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} func({5:void}); | + {7:// I am a }{8:speling}{7: }{8:^mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed(']s') screen:expect([[ {3:#include }{4:<stdbool.h>} | - {5:bool} func({5:void})^; | + {5:bool} func({5:void}); | + {7:// I am a }{8:^speling}{7: }{8:mistakke} | {0:~ }| {0:~ }| {0:~ }| {0:~ }| + {6:search hit BOTTOM, continuing at TOP} | + ]]) + exec('echo ""') + local ns = meths.create_namespace("spell") + -- extmark with spell=true enables spell + local id = curbufmeths.set_extmark(ns, 1, 4, { end_row = 1, end_col = 10, spell = true }) + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} {1:func}({5:void}); | + {7:// I am a }{8:^speling}{7: }{8:mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| {0:~ }| | ]]) feed('[s') screen:expect([[ {3:#include }{4:<stdbool.h>} | - {5:bool} func({5:void})^; | + {5:bool} {1:^func}({5:void}); | + {7:// I am a }{8:speling}{7: }{8:mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + curbufmeths.del_extmark(ns, id) + -- extmark with spell=false disables spell + id = curbufmeths.set_extmark(ns, 2, 18, { end_row = 2, end_col = 26, spell = false }) + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} ^func({5:void}); | + {7:// I am a }{8:speling}{7: mistakke} | {0:~ }| {0:~ }| {0:~ }| {0:~ }| + | + ]]) + feed('[s') + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} func({5:void}); | + {7:// I am a }{8:^speling}{7: mistakke} | + {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() + exec('echo ""') + curbufmeths.del_extmark(ns, id) + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} func({5:void}); | + {7:// I am a }{8:^speling}{7: }{8:mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) feed(']s') screen:expect([[ {3:#include }{4:<stdbool.h>} | - {5:bool} func({5:void})^; | + {5:bool} func({5:void}); | + {7:// I am a }{8:speling}{7: }{8:^mistakke} | + {0:~ }| + {0:~ }| {0:~ }| {0:~ }| + | + ]]) + -- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled + exec('set spelloptions+=noplainbuffer') + screen:expect_unchanged() + feed('[s') + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} func({5:void}); | + {7:// I am a }{8:^speling}{7: }{8:mistakke} | + {0:~ }| {0:~ }| {0:~ }| {0:~ }| - {6:search hit BOTTOM, continuing at TOP} | + | ]]) -- no spellchecking with "noplainbuffer" and syntax disabled - command('syntax off') + exec('syntax off') screen:expect([[ #include <stdbool.h> | - bool func(void)^; | + bool func(void); | + // I am a ^speling mistakke | {0:~ }| {0:~ }| {0:~ }| {0:~ }| - {0:~ }| - {6:search hit BOTTOM, continuing at TOP} | + | ]]) - feed('[s') + feed(']s') screen:expect([[ #include <stdbool.h> | - bool func(void)^; | + bool func(void); | + // I am a ^speling mistakke | {0:~ }| {0:~ }| {0:~ }| {0:~ }| - {0:~ }| - {6:search hit TOP, continuing at BOTTOM} | + {6:search hit BOTTOM, continuing at TOP} | ]]) + exec('echo ""') -- everything is spellchecked without "noplainbuffer" with syntax disabled - command('set spelloptions&') + exec('set spelloptions&') screen:expect([[ #include <{1:stdbool}.h> | - {1:bool} {1:func}(void)^; | - {0:~ }| + {1:bool} {1:func}(void); | + // I am a {1:^speling} {1:mistakke} | {0:~ }| {0:~ }| {0:~ }| {0:~ }| - {6:search hit TOP, continuing at BOTTOM} | + | ]]) - feed(']s') + feed('[s') screen:expect([[ - #include <{1:^stdbool}.h> | - {1:bool} {1:func}(void); | - {0:~ }| + #include <{1:stdbool}.h> | + {1:bool} {1:^func}(void); | + // I am a {1:speling} {1:mistakke} | {0:~ }| {0:~ }| {0:~ }| {0:~ }| - {6:search hit BOTTOM, continuing at TOP} | + | + ]]) + end) + + it('and syntax does not clear extmark highlighting at the start of a word', function() + screen:try_resize(43, 3) + exec([[ + set spell + syntax match Constant "^.*$" + call setline(1, "This is some text without any spell errors.") + ]]) + local ns = meths.create_namespace("spell") + curbufmeths.set_extmark(ns, 0, 0, { hl_group = 'WarningMsg', end_col = 43 }) + screen:expect([[ + {6:^This is some text without any spell errors.}| + {0:~ }| + | ]]) end) end) diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index ae3b95fb0f..6eaf15cfad 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -3,11 +3,15 @@ local Screen = require('test.functional.ui.screen') local clear = helpers.clear local command = helpers.command local eq = helpers.eq +local exec = helpers.exec local eval = helpers.eval local exec_lua = helpers.exec_lua local feed = helpers.feed local meths = helpers.meths local pcall_err = helpers.pcall_err +local assert_alive = helpers.assert_alive + +local mousemodels = { "extend", "popup", "popup_setpos" } describe('statuscolumn', function() local screen @@ -15,6 +19,7 @@ describe('statuscolumn', function() clear('--cmd', 'set number nuw=1 | call setline(1, repeat(["aaaaa"], 16)) | norm GM') screen = Screen.new() screen:attach() + exec_lua('ns = vim.api.nvim_create_namespace("")') end) it("fails with invalid 'statuscolumn'", function() @@ -41,22 +46,17 @@ describe('statuscolumn', function() 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:try_resize(screen._width, 4) + command([=[ + set stc=%{v:relnum?v:relnum:(v:lnum==5?'bbbbb':v:lnum)} + let ns = nvim_create_namespace('') + call nvim_buf_set_extmark(0, ns, 3, 0, {'virt_text':[['virt_text']]}) + norm 5G | redraw! + ]=]) screen:expect([[ - 1 aaaaa | + 1 aaaaa virt_text | 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) @@ -193,8 +193,10 @@ describe('statuscolumn', function() [2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGrey}, [3] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey}, [4] = {bold = true, foreground = Screen.colors.Brown}, - [5] = {background = Screen.colors.Grey90}, + [5] = {foreground = Screen.colors.Red}, + [6] = {foreground = Screen.colors.Red, background = Screen.colors.LightGrey}, }) + command('hi! CursorLine guifg=Red guibg=NONE') screen:expect([[ {1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {1: │ }a | @@ -211,7 +213,7 @@ describe('statuscolumn', function() {1:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}| | ]]) - command("set stc=%C%s%=%l│\\ ") + command([[set stc=%C%s%=%l│\ ]]) screen:expect_unchanged() command('set signcolumn=auto:2 foldcolumn=auto') command('sign define piet1 text=>> texthl=LineNr') @@ -265,7 +267,7 @@ describe('statuscolumn', function() {2: }{1: │}{2: }{1: }aaaaaa | {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: │}{2: }{1: }aaaaaa | - {2:+}{4: 8│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2:+}{4: 8│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: │}{2: }{1: }aaaaaa | {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| @@ -283,7 +285,7 @@ describe('statuscolumn', function() {2: }{1: 6│}{2: }{1: }aaaaaa | {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: 7│}{2: }{1: }aaaaaa | - {2:+}{4: 8│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2:+}{4: 8│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: 9│}{2: }{1: }aaaaaa | {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| @@ -301,7 +303,7 @@ describe('statuscolumn', function() {2: }{1: 2│}{2: }{1: }aaaaaa | {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: 1│}{2: }{1: }aaaaaa | - {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: 1│}{2: }{1: }aaaaaa | {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| @@ -318,7 +320,7 @@ describe('statuscolumn', function() {2: }{1: │}{2: }{1: }aaaaaa | {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: │}{2: }{1: }aaaaaa | - {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: │}{2: }{1: }aaaaaa | {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| @@ -343,16 +345,74 @@ describe('statuscolumn', function() {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaa}| + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaa}| {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | | ]]) + -- Also test fold and sign column when 'cpoptions' includes "n" + command('set cpoptions+=n') + feed('Hgjg0') + screen:expect([[ + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{5:^aaaaaaaaaaaaaaaaaaaa }| + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + | + ]]) + command('set breakindent') + command('sign unplace 2') + feed('J2gjg0') + screen:expect([[ + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: } {5:aaaaaaaaaaaaaaaaaaaa aaaaaaaaa}| + {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: } {5:^aaaaaaaaaaa }| + {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| + {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaa | + | + ]]) + command('set nobreakindent') + feed('$g0') + screen:expect([[ + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{5:aaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaa}| + {2: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{5:^aaa }| + {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| + {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaa | + | + ]]) + command('silent undo') + feed('8gg') + command('set cpoptions-=n') -- 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", ""}}} }) @@ -365,57 +425,216 @@ describe('statuscolumn', function() {1:buffer 0 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {1:wrapped 1 5}aaaaaaaa | {1:virtual-2 5}virt_line | - {1:virtual-2 5}virt_line above | + {1:virtual-1 5}virt_line above | {1:buffer 0 6}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {1:wrapped 1 6}aaaaaaaa | {1:buffer 0 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {1:wrapped 1 7}aaaaaaaa | - {4:buffer 0 8}{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {4:buffer 0 8}{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| {1:buffer 0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {1:wrapped 1 9}aaaaaaaa | | ]]) + -- Also test virt_lines at the end of buffer + exec_lua([[ + vim.api.nvim_buf_set_extmark(0, ns, 15, 0, { virt_lines = {{{"END", ""}}} }) + ]]) + feed('GkJzz') + screen:expect([[ + {1:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:wrapped 1 12}aaaaaaaaa | + {1:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:wrapped 1 13}aaaaaaaaa | + {1:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:wrapped 1 14}aaaaaaaaa | + {4:buffer 0 15}{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {4:wrapped 1 15}{5:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {4:wrapped 2 15}{5:aaaaaaaaaaaaaaaaaaa }| + {1:virtual-1 15}END | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- Also test virt_lines when 'cpoptions' includes "n" + exec_lua([[ + vim.opt.cpoptions:append("n") + vim.api.nvim_buf_set_extmark(0, ns, 14, 0, { virt_lines = {{{"virt_line1", ""}}} }) + vim.api.nvim_buf_set_extmark(0, ns, 14, 0, { virt_lines = {{{"virt_line2", ""}}} }) + ]]) + screen:expect([[ + {1:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + aaaaaaaaa | + {1:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + aaaaaaaaa | + {1:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + aaaaaaaaa | + {4:buffer 0 15}{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {5:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {5:aaaaaaa }| + {1:virtual-3 15}virt_line1 | + {1:virtual-2 15}virt_line2 | + {1:virtual-1 15}END | + {0:~ }| + | + ]]) 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")) + it('does not corrupt the screen with minwid sign item', function() + screen:try_resize(screen._width, 3) + screen:set_default_attr_ids({ + [0] = {foreground = Screen.colors.Brown}, + [1] = {foreground = Screen.colors.Blue4, background = Screen.colors.Gray}, + }) + command([[set stc=%6s\ %l]]) + exec_lua('vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {sign_text = "𒀀"})') + screen:expect([[ + {0: 𒀀 8}^aaaaa | + {0: }{1: }{0: 9}aaaaa | + | + ]]) end) - it('click labels do not leak memory', function() - command([[ + for _, model in ipairs(mousemodels) do + describe('with mousemodel=' .. model, function() + before_each(function() + command('set mousemodel=' .. model) + exec([[ + 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 + let g:testvar = '' + ]]) + end) + + it('clicks work with mousemodel=' .. model, function() + meths.set_option_value('statuscolumn', '%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('rightbelow vsplit') + meths.input_mouse('left', 'press', '', 0, 0, 27) + eq('0 1 l 4', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 3, 27) + eq('0 1 r 7', eval("g:testvar")) + command('setlocal rightleft') + meths.input_mouse('left', 'press', '', 0, 0, 52) + eq('0 1 l 4', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 3, 52) + eq('0 1 r 7', eval("g:testvar")) + command('wincmd H') + meths.input_mouse('left', 'press', '', 0, 0, 25) + eq('0 1 l 4', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 3, 25) + eq('0 1 r 7', eval("g:testvar")) + command('close') + + command('set laststatus=2 winbar=%f') + command('let g:testvar = ""') + -- Check that winbar click doesn't register as statuscolumn click + meths.input_mouse('right', 'press', '', 0, 0, 0) + eq('', eval("g:testvar")) + -- Check that statusline click doesn't register as statuscolumn click + meths.input_mouse('right', 'press', '', 0, 12, 0) + eq('', eval("g:testvar")) + -- Check that cmdline click doesn't register as statuscolumn click + meths.input_mouse('right', 'press', '', 0, 13, 0) + eq('', eval("g:testvar")) + end) + + it('clicks and highlights work with control characters', function() + meths.set_option_value('statuscolumn', '\t%#NonText#\1%0@MyClickFunc@\t\1%T\t%##\1', {}) + screen:expect{grid=[[ + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}^aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + {1:^I}{0:^A^I^A^I}{1:^A}aaaaa | + | + ]], attr_ids={ + [0] = {foreground = Screen.colors.Blue, bold = true}; -- NonText + [1] = {foreground = Screen.colors.Brown}; -- LineNr + }} + meths.input_mouse('right', 'press', '', 0, 4, 3) + eq('', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 5, 8) + eq('', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 4) + eq('0 1 r 10', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 7, 7) + eq('0 1 l 11', eval("g:testvar")) + end) + + it('popupmenu callback does not drag mouse on close', function() + screen:try_resize(screen._width, 2) + screen:set_default_attr_ids({ + [0] = {foreground = Screen.colors.Brown}, + [1] = {background = Screen.colors.Plum1}, + }) + meths.set_option_value('statuscolumn', '%0@MyClickFunc@%l%T', {}) + exec([[ + function! MyClickFunc(minwid, clicks, button, mods) + let g:testvar = printf("%d %d %s %d", a:minwid, a:clicks, a:button, getmousepos().line) + menu PopupStc.Echo <cmd>echo g:testvar<CR> + popup PopupStc + endfunction + ]]) + -- clicking an item does not drag mouse + meths.input_mouse('left', 'press', '', 0, 0, 0) + screen:expect([[ + {0:8 }^aaaaa | + {1: Echo } | + ]]) + meths.input_mouse('left', 'press', '', 0, 1, 5) + meths.input_mouse('left', 'release', '', 0, 1, 5) + screen:expect([[ + {0:8 }^aaaaa | + 0 1 l 8 | + ]]) + command('echo') + -- clicking outside to close the menu does not drag mouse + meths.input_mouse('left', 'press', '', 0, 0, 0) + screen:expect([[ + {0:8 }^aaaaa | + {1: Echo } | + ]]) + meths.input_mouse('left', 'press', '', 0, 0, 10) + meths.input_mouse('left', 'release', '', 0, 0, 10) + screen:expect([[ + {0:8 }^aaaaa | + | + ]]) + end) + end) + end + + it('click labels do not leak memory #21878', function() + exec([[ set laststatus=2 setlocal statuscolumn=%0@MyClickFunc@abcd%T 4vsplit @@ -427,19 +646,29 @@ describe('statuscolumn', function() ]]) end) + it('click labels do not crash when initial width is 0 #24428', function() + exec([[ + set nonumber + bwipe! + setlocal statuscolumn=abcd + redraw + setlocal statuscolumn=%0@MyClickFunc@abcd%T + redraw + ]]) + assert_alive() + 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 | @@ -456,7 +685,188 @@ describe('statuscolumn', function() 14 aaaaa | | ]]) - command('set stc=') -- also for the default sign column + command('set stc=') -- also for the default fold column screen:expect_unchanged() + -- 'statuscolumn' is not too wide with custom (bogus) fold column + command([[set stc=%{foldlevel(v:lnum)>0?repeat('-',foldlevel(v:lnum)):''}%=%l\ ]]) + feed('Gd10Ggg<C-l>') + screen:expect([[ + 1 ^aaaaa | + 2 aaaaa | + 3 aaaaa | + 4 aaaaa | + 5 aaaaa | + 6 aaaaa | + 7 aaaaa | + virt | + ---------8 aaaaa | + virt | + ---------9 aaaaa | + ~ | + ~ | + | + ]]) + end) + + it('works with cmdwin', function() + feed(':set stc=%l<CR>q:k$') + screen:expect([[ + 7 aaaaa | + 8 aaaaa | + 9 aaaaa | + 10aaaaa | + [No Name] [+] | + :1set stc=%^l | + :2 | + ~ | + ~ | + ~ | + ~ | + ~ | + [Command Line] | + : | + ]]) + end) + + it("has correct width when toggling '(relative)number'", function() + screen:try_resize(screen._width, 6) + command('call setline(1, repeat(["aaaaa"], 100))') + command('set relativenumber') + command([[set stc=%{!&nu&&!&rnu?'':&rnu?v:relnum?v:relnum:&nu?v:lnum:'0':v:lnum}]]) + screen:expect([[ + 1 aaaaa | + 8 ^aaaaa | + 1 aaaaa | + 2 aaaaa | + 3 aaaaa | + | + ]]) + -- width correctly estimated with "w_nrwidth_line_count" when setting 'stc' + command([[set stc=%{!&nu&&!&rnu?'':&rnu?v:relnum?v:relnum:&nu?v:lnum:'0':v:lnum}]]) + screen:expect_unchanged() + -- zero width when disabling 'number' + command('set norelativenumber nonumber') + screen:expect([[ + aaaaa | + ^aaaaa | + aaaaa | + aaaaa | + aaaaa | + | + ]]) + -- width correctly estimated with "w_nrwidth_line_count" when setting 'nu' + command('set number') + screen:expect([[ + 7 aaaaa | + 8 ^aaaaa | + 9 aaaaa | + 10 aaaaa | + 11 aaaaa | + | + ]]) + end) + + it("has correct width with custom sign column when (un)placing signs", function() + screen:try_resize(screen._width, 3) + exec_lua([[ + vim.cmd.norm('gg') + vim.o.signcolumn = 'no' + vim.fn.sign_define('sign', { text = 'ss' }) + _G.StatusCol = function() + local s = vim.fn.sign_getplaced(1)[1].signs + local es = vim.api.nvim_buf_get_extmarks(0, ns, 0, -1, {type = "sign"}) + local sign = '' + local signs = #s + #es + if signs > 0 then + sign = (vim.v.lnum == 2 and 'ss' or ' '):rep(signs) + end + return vim.v.lnum .. '%=' .. sign + end + vim.o.number = true + vim.o.numberwidth = 2 + vim.o.statuscolumn = "%!v:lua.StatusCol()" + ]]) + command('sign place 1 line=2 name=sign') + screen:expect([[ + 1 ^aaaaa | + 2 ssaaaaa | + | + ]]) + command('sign place 2 line=2 name=sign') + screen:expect([[ + 1 ^aaaaa | + 2 ssssaaaaa | + | + ]]) + command('sign unplace 2') + screen:expect([[ + 1 ^aaaaa | + 2 ssaaaaa | + | + ]]) + command('sign unplace 1') + screen:expect([[ + 1 ^aaaaa | + 2 aaaaa | + | + ]]) + -- Also for extmark signs + exec_lua('id1 = vim.api.nvim_buf_set_extmark(0, ns, 1, 0, {sign_text = "ss"})') + screen:expect([[ + 1 ^aaaaa | + 2 ssaaaaa | + | + ]]) + exec_lua('id2 = vim.api.nvim_buf_set_extmark(0, ns, 1, 0, {sign_text = "ss"})') + screen:expect([[ + 1 ^aaaaa | + 2 ssssaaaaa | + | + ]]) + exec_lua("vim.api.nvim_buf_del_extmark(0, ns, id1)") + screen:expect([[ + 1 ^aaaaa | + 2 ssaaaaa | + | + ]]) + exec_lua("vim.api.nvim_buf_del_extmark(0, ns, id2)") + screen:expect([[ + 1 ^aaaaa | + 2 aaaaa | + | + ]]) + -- In all windows + command('wincmd v | set ls=0') + command('sign place 1 line=2 name=sign') + screen:expect([[ + 1 ^aaaaa │1 aaaaa | + 2 ssaaaaa │2 ssaaaaa | + | + ]]) + end) + + it("is only evaluated twice, once to estimate and once to draw", function() + command([[ + let g:stcnr = 0 + func! Stc() + let g:stcnr += 1 + return '12345' + endfunc + set stc=%!Stc() + norm ggdG + ]]) + eq(2, eval('g:stcnr')) + end) + + it('does not wrap multibyte characters at the end of a line', function() + screen:try_resize(33, 4) + command([[set spell stc=%l\ ]]) + command('call setline(8, "This is a line that contains ᶏ multibyte character.")') + screen:expect([[ + 8 ^This is a line that contains ᶏ| + multibyte character. | + 9 aaaaa | + | + ]]) end) end) diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index 1c184ff27d..182e0cdadf 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -10,179 +10,215 @@ local meths = helpers.meths local exec = helpers.exec local exec_lua = helpers.exec_lua local eval = helpers.eval - -describe('statusline clicks', function() - local screen - - before_each(function() - clear() - screen = Screen.new(40, 8) - screen:attach() - command('set laststatus=2 mousemodel=extend') - exec([=[ - function! MyClickFunc(minwid, clicks, button, mods) - let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button) - if a:mods !=# ' ' - let g:testvar ..= '(' .. a:mods .. ')' - endif - endfunction - ]=]) - end) - - it('works', function() - meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T') - meths.input_mouse('left', 'press', '', 0, 6, 17) - eq('0 1 l', eval("g:testvar")) - meths.input_mouse('left', 'press', '', 0, 6, 17) - eq('0 2 l', eval("g:testvar")) - meths.input_mouse('left', 'press', '', 0, 6, 17) - eq('0 3 l', eval("g:testvar")) - meths.input_mouse('left', 'press', '', 0, 6, 17) - eq('0 4 l', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 6, 17) - eq('0 1 r', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 6, 17) - eq('0 2 r', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 6, 17) - eq('0 3 r', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 6, 17) - eq('0 4 r', eval("g:testvar")) - end) - - it('works for winbar', function() - meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T') - meths.input_mouse('left', 'press', '', 0, 0, 17) - eq('0 1 l', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 0, 17) - eq('0 1 r', eval("g:testvar")) - end) - - it('works for winbar in floating window', function() - meths.open_win(0, true, { width=30, height=4, relative='editor', row=1, col=5, - border = "single" }) - meths.set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', - { scope = 'local' }) - meths.input_mouse('left', 'press', '', 0, 2, 23) - eq('0 1 l', eval("g:testvar")) - end) - - it('works when there are multiple windows', function() - command('split') - meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T') - meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T') - meths.input_mouse('left', 'press', '', 0, 0, 17) - eq('0 1 l', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 4, 17) - eq('0 1 r', eval("g:testvar")) - meths.input_mouse('middle', 'press', '', 0, 3, 17) - eq('0 1 m', eval("g:testvar")) - meths.input_mouse('left', 'press', '', 0, 6, 17) - eq('0 1 l', eval("g:testvar")) - end) - - it('works with Lua function', function() - exec_lua([[ +local sleep = helpers.sleep + +local mousemodels = { "extend", "popup", "popup_setpos" } + +for _, model in ipairs(mousemodels) do + describe('statusline clicks with mousemodel=' .. model, function() + local screen + + before_each(function() + clear() + screen = Screen.new(40, 8) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}; -- NonText + [1] = {bold = true, reverse = true}; -- StatusLine + }) + screen:attach() + command('set laststatus=2 mousemodel=' .. model) + exec([=[ + function! MyClickFunc(minwid, clicks, button, mods) + let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button) + if a:mods !=# ' ' + let g:testvar ..= '(' .. a:mods .. ')' + endif + endfunction + let g:testvar = '' + ]=]) + end) + + it('works', function() + meths.set_option_value('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {}) + meths.input_mouse('left', 'press', '', 0, 6, 16) + eq('', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 29) + eq('', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 1 l', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 2 l', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 3 l', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 4 l', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 28) + eq('0 1 r', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 28) + eq('0 2 r', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 28) + eq('0 3 r', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 28) + eq('0 4 r', eval("g:testvar")) + end) + + it('works with control characters and highlight', function() + meths.set_option_value('statusline', '\t%#NonText#\1%0@MyClickFunc@\t\1%T\t%##\1', {}) + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1:^I}{0:^A^I^A^I}{1:^A }| + | + ]]} + meths.input_mouse('right', 'press', '', 0, 6, 3) + eq('', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 8) + eq('', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 4) + eq('0 1 r', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 7) + eq('0 1 l', eval("g:testvar")) + end) + + it('works for winbar', function() + meths.set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {}) + meths.input_mouse('left', 'press', '', 0, 0, 17) + eq('0 1 l', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 0, 17) + eq('0 1 r', eval("g:testvar")) + end) + + it('works for winbar in floating window', function() + meths.open_win(0, true, { width=30, height=4, relative='editor', row=1, col=5, + border = "single" }) + meths.set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', + { scope = 'local' }) + meths.input_mouse('left', 'press', '', 0, 2, 23) + eq('0 1 l', eval("g:testvar")) + end) + + it('works when there are multiple windows', function() + command('split') + meths.set_option_value('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {}) + meths.set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {}) + meths.input_mouse('left', 'press', '', 0, 0, 17) + eq('0 1 l', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 4, 17) + eq('0 1 r', eval("g:testvar")) + meths.input_mouse('middle', 'press', '', 0, 3, 17) + eq('0 1 m', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 1 l', eval("g:testvar")) + end) + + it('works with Lua function', function() + exec_lua([[ function clicky_func(minwid, clicks, button, mods) vim.g.testvar = string.format("%d %d %s", minwid, clicks, button) end - ]]) - meths.set_option('statusline', 'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T') - meths.input_mouse('left', 'press', '', 0, 6, 17) - eq('0 1 l', eval("g:testvar")) - end) - - it('ignores unsupported click items', function() - command('tabnew | tabprevious') - meths.set_option('statusline', '%2TNot clicky stuff%T') - meths.input_mouse('left', 'press', '', 0, 6, 0) - eq(1, meths.get_current_tabpage().id) - meths.set_option('statusline', '%2XNot clicky stuff%X') - meths.input_mouse('left', 'press', '', 0, 6, 0) - eq(2, #meths.list_tabpages()) - end) - - it("right click works when statusline isn't focused #18994", function() - meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T') - meths.input_mouse('right', 'press', '', 0, 6, 17) - eq('0 1 r', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 6, 17) - eq('0 2 r', eval("g:testvar")) - end) - - it("works with modifiers #18994", function() - meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T') - -- Note: alternate between left and right mouse buttons to avoid triggering multiclicks - meths.input_mouse('left', 'press', 'S', 0, 6, 17) - eq('0 1 l(s )', eval("g:testvar")) - meths.input_mouse('right', 'press', 'S', 0, 6, 17) - eq('0 1 r(s )', eval("g:testvar")) - meths.input_mouse('left', 'press', 'A', 0, 6, 17) - eq('0 1 l( a )', eval("g:testvar")) - meths.input_mouse('right', 'press', 'A', 0, 6, 17) - eq('0 1 r( a )', eval("g:testvar")) - meths.input_mouse('left', 'press', 'AS', 0, 6, 17) - eq('0 1 l(s a )', eval("g:testvar")) - meths.input_mouse('right', 'press', 'AS', 0, 6, 17) - eq('0 1 r(s a )', eval("g:testvar")) - meths.input_mouse('left', 'press', 'T', 0, 6, 17) - eq('0 1 l( m)', eval("g:testvar")) - meths.input_mouse('right', 'press', 'T', 0, 6, 17) - eq('0 1 r( m)', eval("g:testvar")) - meths.input_mouse('left', 'press', 'TS', 0, 6, 17) - eq('0 1 l(s m)', eval("g:testvar")) - meths.input_mouse('right', 'press', 'TS', 0, 6, 17) - eq('0 1 r(s m)', eval("g:testvar")) - meths.input_mouse('left', 'press', 'C', 0, 6, 17) - eq('0 1 l( c )', eval("g:testvar")) - -- <C-RightMouse> is for tag jump - end) - - it("works for global statusline with vertical splits #19186", function() - command('set laststatus=3') - meths.set_option('statusline', '%0@MyClickFunc@Clicky stuff%T %= %0@MyClickFunc@Clicky stuff%T') - command('vsplit') - screen:expect([[ - ^ │ | - ~ │~ | - ~ │~ | - ~ │~ | - ~ │~ | - ~ │~ | - Clicky stuff Clicky stuff| - | - ]]) - - -- clickable area on the right - meths.input_mouse('left', 'press', '', 0, 6, 35) - eq('0 1 l', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 6, 35) - eq('0 1 r', eval("g:testvar")) - - -- clickable area on the left - meths.input_mouse('left', 'press', '', 0, 6, 5) - eq('0 1 l', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 6, 5) - eq('0 1 r', eval("g:testvar")) - end) - - it('no memory leak with zero-width click labels', function() - command([[ + ]]) + meths.set_option_value('statusline', 'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T', {}) + meths.input_mouse('left', 'press', '', 0, 6, 17) + eq('0 1 l', eval("g:testvar")) + end) + + it('ignores unsupported click items', function() + command('tabnew | tabprevious') + meths.set_option_value('statusline', '%2TNot clicky stuff%T', {}) + meths.input_mouse('left', 'press', '', 0, 6, 0) + eq(1, meths.get_current_tabpage().id) + meths.set_option_value('statusline', '%2XNot clicky stuff%X', {}) + meths.input_mouse('left', 'press', '', 0, 6, 0) + eq(2, #meths.list_tabpages()) + end) + + it("right click works when statusline isn't focused #18994", function() + meths.set_option_value('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {}) + meths.input_mouse('right', 'press', '', 0, 6, 17) + eq('0 1 r', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 17) + eq('0 2 r', eval("g:testvar")) + end) + + it("works with modifiers #18994", function() + meths.set_option_value('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {}) + -- Note: alternate between left and right mouse buttons to avoid triggering multiclicks + meths.input_mouse('left', 'press', 'S', 0, 6, 17) + eq('0 1 l(s )', eval("g:testvar")) + meths.input_mouse('right', 'press', 'S', 0, 6, 17) + eq('0 1 r(s )', eval("g:testvar")) + meths.input_mouse('left', 'press', 'A', 0, 6, 17) + eq('0 1 l( a )', eval("g:testvar")) + meths.input_mouse('right', 'press', 'A', 0, 6, 17) + eq('0 1 r( a )', eval("g:testvar")) + meths.input_mouse('left', 'press', 'AS', 0, 6, 17) + eq('0 1 l(s a )', eval("g:testvar")) + meths.input_mouse('right', 'press', 'AS', 0, 6, 17) + eq('0 1 r(s a )', eval("g:testvar")) + meths.input_mouse('left', 'press', 'T', 0, 6, 17) + eq('0 1 l( m)', eval("g:testvar")) + meths.input_mouse('right', 'press', 'T', 0, 6, 17) + eq('0 1 r( m)', eval("g:testvar")) + meths.input_mouse('left', 'press', 'TS', 0, 6, 17) + eq('0 1 l(s m)', eval("g:testvar")) + meths.input_mouse('right', 'press', 'TS', 0, 6, 17) + eq('0 1 r(s m)', eval("g:testvar")) + meths.input_mouse('left', 'press', 'C', 0, 6, 17) + eq('0 1 l( c )', eval("g:testvar")) + -- <C-RightMouse> is for tag jump + end) + + it("works for global statusline with vertical splits #19186", function() + command('set laststatus=3') + meths.set_option_value('statusline', '%0@MyClickFunc@Clicky stuff%T %= %0@MyClickFunc@Clicky stuff%T', {}) + command('vsplit') + screen:expect{grid=[[ + ^ │ | + {0:~ }│{0:~ }| + {0:~ }│{0:~ }| + {0:~ }│{0:~ }| + {0:~ }│{0:~ }| + {0:~ }│{0:~ }| + {1:Clicky stuff Clicky stuff}| + | + ]]} + + -- clickable area on the right + meths.input_mouse('left', 'press', '', 0, 6, 35) + eq('0 1 l', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 35) + eq('0 1 r', eval("g:testvar")) + + -- clickable area on the left + meths.input_mouse('left', 'press', '', 0, 6, 5) + eq('0 1 l', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 5) + eq('0 1 r', eval("g:testvar")) + end) + + it('no memory leak with zero-width click labels', function() + command([[ let &stl = '%@Test@%T%@MyClickFunc@%=%T%@Test@' - ]]) - meths.input_mouse('left', 'press', '', 0, 6, 0) - eq('0 1 l', eval("g:testvar")) - meths.input_mouse('right', 'press', '', 0, 6, 39) - eq('0 1 r', eval("g:testvar")) - end) - - it('no memory leak with truncated click labels', function() - command([[ + ]]) + 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")) + ]]) + meths.input_mouse('left', 'press', '', 0, 6, 2) + eq('0 1 l', eval("g:testvar")) + end) end) -end) +end describe('global statusline', function() local screen @@ -389,38 +425,38 @@ describe('global statusline', function() end) it('win_move_statusline() can reduce cmdheight to 1', function() - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) funcs.win_move_statusline(0, -1) - eq(2, meths.get_option('cmdheight')) + eq(2, meths.get_option_value('cmdheight', {})) funcs.win_move_statusline(0, -1) - eq(3, meths.get_option('cmdheight')) + eq(3, meths.get_option_value('cmdheight', {})) funcs.win_move_statusline(0, 1) - eq(2, meths.get_option('cmdheight')) + eq(2, meths.get_option_value('cmdheight', {})) funcs.win_move_statusline(0, 1) - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) end) it('mouse dragging can reduce cmdheight to 1', function() command('set mouse=a') meths.input_mouse('left', 'press', '', 0, 14, 10) - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) meths.input_mouse('left', 'drag', '', 0, 13, 10) - eq(2, meths.get_option('cmdheight')) + eq(2, meths.get_option_value('cmdheight', {})) meths.input_mouse('left', 'drag', '', 0, 12, 10) - eq(3, meths.get_option('cmdheight')) + eq(3, meths.get_option_value('cmdheight', {})) meths.input_mouse('left', 'drag', '', 0, 13, 10) - eq(2, meths.get_option('cmdheight')) + eq(2, meths.get_option_value('cmdheight', {})) meths.input_mouse('left', 'drag', '', 0, 14, 10) - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) meths.input_mouse('left', 'drag', '', 0, 15, 10) - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) meths.input_mouse('left', 'drag', '', 0, 14, 10) - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) end) it('cmdline row is correct after setting cmdheight #20514', function() command('botright split test/functional/fixtures/bigfile.txt') - meths.set_option('cmdheight', 1) + meths.set_option_value('cmdheight', 1, {}) feed('L') screen:expect([[ | @@ -459,7 +495,7 @@ describe('global statusline', function() {2:test/functional/fixtures/bigfile.txt 8,1 0%}| | ]]) - meths.set_option('showtabline', 2) + meths.set_option_value('showtabline', 2, {}) screen:expect([[ {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| | @@ -478,7 +514,7 @@ describe('global statusline', function() {2:test/functional/fixtures/bigfile.txt 8,1 0%}| | ]]) - meths.set_option('cmdheight', 0) + meths.set_option_value('cmdheight', 0, {}) screen:expect([[ {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| | @@ -497,7 +533,7 @@ describe('global statusline', function() ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | {2:test/functional/fixtures/bigfile.txt 8,1 0%}| ]]) - meths.set_option('cmdheight', 1) + meths.set_option_value('cmdheight', 1, {}) screen:expect([[ {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| | @@ -521,8 +557,8 @@ end) it('statusline does not crash if it has Arabic characters #19447', function() clear() - meths.set_option('statusline', 'غً') - meths.set_option('laststatus', 2) + meths.set_option_value('statusline', 'غً', {}) + meths.set_option_value('laststatus', 2, {}) command('redraw!') assert_alive() end) @@ -589,3 +625,195 @@ it('showcmdloc=statusline does not show if statusline is too narrow', function() feed('1234') screen:expect_unchanged() end) + +it('K_EVENT does not trigger a statusline redraw unnecessarily', function() + clear() + local screen = Screen.new(40, 8) + screen:attach() + -- does not redraw on vim.schedule (#17937) + command([[ + set laststatus=2 + let g:counter = 0 + func Status() + let g:counter += 1 + lua vim.schedule(function() end) + return g:counter + endfunc + set statusline=%!Status() + ]]) + sleep(50) + eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter')) + -- also in insert mode + feed('i') + sleep(50) + eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter')) + -- does not redraw on timer call (#14303) + command([[ + let g:counter = 0 + func Timer(timer) + endfunc + call timer_start(1, 'Timer', {'repeat': 100}) + ]]) + sleep(50) + eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter')) +end) + +it('statusline is redrawn on various state changes', function() + clear() + local screen = Screen.new(40, 4) + screen:attach() + + -- recording state change #22683 + command('set ls=2 stl=%{repeat(reg_recording(),5)}') + screen:expect([[ + ^ | + ~ | + | + | + ]]) + feed('qQ') + screen:expect([[ + ^ | + ~ | + QQQQQ | + recording @Q | + ]]) + feed('q') + screen:expect([[ + ^ | + ~ | + | + | + ]]) + + -- Visual mode change #23932 + command('set ls=2 stl=%{mode(1)}') + screen:expect([[ + ^ | + ~ | + n | + | + ]]) + feed('v') + screen:expect([[ + ^ | + ~ | + v | + -- VISUAL -- | + ]]) + feed('V') + screen:expect([[ + ^ | + ~ | + V | + -- VISUAL LINE -- | + ]]) + feed('<C-V>') + screen:expect([[ + ^ | + ~ | + ^V | + -- VISUAL BLOCK -- | + ]]) + feed('<Esc>') + screen:expect([[ + ^ | + ~ | + n | + | + ]]) +end) + +it('ruler is redrawn in cmdline with redrawstatus #22804', function() + clear() + local screen = Screen.new(40, 2) + screen:attach() + command([[ + let g:n = 'initial value' + set ls=1 ru ruf=%{g:n} + redraw + let g:n = 'other value' + redrawstatus + ]]) + screen:expect([[ + ^ | + other value | + ]]) +end) + +it("shows correct ruler in cmdline with no statusline", function() + clear() + local screen = Screen.new(30, 8) + screen:set_default_attr_ids { + [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [2] = {bold = true, reverse = true}, -- StatusLine + [3] = {reverse = true}, -- StatusLineNC + } + screen:attach() + -- Use long ruler to check 'ruler' with 'rulerformat' set has correct width. + command [[ + set ruler rulerformat=%{winnr()}longlonglong ls=0 winwidth=10 + split + wincmd b + vsplit + wincmd t + wincmd | + mode + ]] + -- Window 1 is current. It has a statusline, so cmdline should show the + -- last window's ruler, which has no statusline. + command '1wincmd w' + screen:expect [[ + ^ | + {1:~ }| + {1:~ }| + {2:[No Name] 1longlonglong }| + │ | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + 3longlonglong | + ]] + -- Window 2 is current. It has no statusline, so cmdline should show its + -- ruler instead. + command '2wincmd w' + screen:expect [[ + | + {1:~ }| + {1:~ }| + {3:[No Name] 1longlonglong }| + ^ │ | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + 2longlonglong | + ]] + -- Window 3 is current. Cmdline should again show its ruler. + command '3wincmd w' + screen:expect [[ + | + {1:~ }| + {1:~ }| + {3:[No Name] 1longlonglong }| + │^ | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + 3longlonglong | + ]] +end) + +it('uses "stl" and "stlnc" fillchars even if they are the same #19803', function() + clear() + local screen = Screen.new(53, 4) + screen:attach() + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + }) + command('hi clear StatusLine') + command('hi clear StatusLineNC') + command('vsplit') + screen:expect{grid=[[ + ^ │ | + {1:~ }│{1:~ }| + [No Name] [No Name] | + | + ]]} +end) diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua index 2cdec62d01..befdb7c5d1 100644 --- a/test/functional/ui/tabline_spec.lua +++ b/test/functional/ui/tabline_spec.lua @@ -1,6 +1,9 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, command, eq = helpers.clear, helpers.command, helpers.eq +local insert = helpers.insert +local meths = helpers.meths +local assert_alive = helpers.assert_alive describe('ui/ext_tabline', function() local screen @@ -92,6 +95,10 @@ describe("tabline", function() clear() screen = Screen.new(42, 5) screen:attach() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}; -- NonText + [1] = {reverse = true}; -- TabLineFill + }) end) it('redraws when tabline option is set', function() @@ -100,24 +107,18 @@ describe("tabline", function() screen:expect{grid=[[ {1:asdf }| ^ | - {2:~ }| - {2:~ }| + {0:~ }| + {0:~ }| | - ]], attr_ids={ - [1] = {reverse = true}; - [2] = {bold = true, foreground = Screen.colors.Blue1}; - }} + ]]} command('set tabline=jkl') screen:expect{grid=[[ {1:jkl }| ^ | - {2:~ }| - {2:~ }| + {0:~ }| + {0:~ }| | - ]], attr_ids={ - [1] = {reverse = true}; - [2] = {bold = true, foreground = Screen.colors.Blue}; - }} + ]]} end) it('click definitions do not leak memory #21765', function() @@ -125,4 +126,52 @@ describe("tabline", function() command('set showtabline=2') command('redrawtabline') end) + + it('clicks work with truncated double-width label #24187', function() + insert('tab1') + command('tabnew') + insert('tab2') + command('tabprev') + meths.set_option_value('tabline', '%1T口口%2Ta' .. ('b'):rep(38) .. '%999Xc', {}) + screen:expect{grid=[[ + {1:<abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc }| + tab^1 | + {0:~ }| + {0:~ }| + | + ]]} + assert_alive() + meths.input_mouse('left', 'press', '', 0, 0, 1) + screen:expect{grid=[[ + {1:<abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc }| + tab^2 | + {0:~ }| + {0:~ }| + | + ]]} + meths.input_mouse('left', 'press', '', 0, 0, 0) + screen:expect{grid=[[ + {1:<abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc }| + tab^1 | + {0:~ }| + {0:~ }| + | + ]]} + meths.input_mouse('left', 'press', '', 0, 0, 39) + screen:expect{grid=[[ + {1:<abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc }| + tab^2 | + {0:~ }| + {0:~ }| + | + ]]} + meths.input_mouse('left', 'press', '', 0, 0, 40) + screen:expect{grid=[[ + tab^1 | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end) end) diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua new file mode 100644 index 0000000000..66c0ff5c9c --- /dev/null +++ b/test/functional/ui/title_spec.lua @@ -0,0 +1,138 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear = helpers.clear +local command = helpers.command +local curwin = helpers.curwin +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local feed = helpers.feed +local funcs = helpers.funcs +local meths = helpers.meths +local is_os = helpers.is_os + +describe('title', function() + local screen + + before_each(function() + clear() + screen = Screen.new() + screen:attach() + end) + + it('has correct default title with unnamed file', function() + local expected = '[No Name] - NVIM' + command('set title') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + it('has correct default title with named file', function() + local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM') + command('set title') + command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + describe('is not changed by', function() + local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1' + local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2' + local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM') + local buf2 + + before_each(function() + command('edit '..file1) + buf2 = funcs.bufadd(file2) + command('set title') + end) + + it('calling setbufvar() to set an option in a hidden buffer from i_CTRL-R', function() + command([[inoremap <F2> <C-R>=setbufvar(]]..buf2..[[, '&autoindent', 1) ?? ''<CR>]]) + feed('i<F2><Esc>') + command('redraw!') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + it('an RPC call to nvim_set_option_value in a hidden buffer', function() + meths.set_option_value('autoindent', true, { buf = buf2 }) + command('redraw!') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + it('a Lua callback calling nvim_set_option_value in a hidden buffer', function() + exec_lua(string.format([[ + vim.schedule(function() + vim.api.nvim_set_option_value('autoindent', true, { buf = %d }) + end) + ]], buf2)) + command('redraw!') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + it('a Lua callback calling nvim_buf_call in a hidden buffer', function() + exec_lua(string.format([[ + vim.schedule(function() + vim.api.nvim_buf_call(%d, function() end) + end) + ]], buf2)) + command('redraw!') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + it('setting the buffer of another window using RPC', function() + local oldwin = curwin().id + command('split') + meths.win_set_buf(oldwin, buf2) + command('redraw!') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + it('setting the buffer of another window using Lua callback', function() + local oldwin = curwin().id + command('split') + exec_lua(string.format([[ + vim.schedule(function() + vim.api.nvim_win_set_buf(%d, %d) + end) + ]], oldwin, buf2)) + command('redraw!') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + it('creating a floating window using RPC', function() + meths.open_win(buf2, false, { + relative = 'editor', width = 5, height = 5, row = 0, col = 0, + }) + command('redraw!') + screen:expect(function() + eq(expected, screen.title) + end) + end) + + it('creating a floating window using Lua callback', function() + exec_lua(string.format([[ + vim.api.nvim_open_win(%d, false, { + relative = 'editor', width = 5, height = 5, row = 0, col = 0, + }) + ]], buf2)) + command('redraw!') + screen:expect(function() + eq(expected, screen.title) + end) + end) + end) +end) diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 50466c9473..3201135b67 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -17,6 +17,85 @@ describe("'wildmenu'", function() screen:attach() end) + -- oldtest: Test_wildmenu_screendump() + it('works', function() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}; -- NonText + [1] = {foreground = Screen.colors.Black, background = Screen.colors.Yellow}; -- WildMenu + [2] = {bold = true, reverse = true}; -- StatusLine + }) + -- Test simple wildmenu + feed(':sign <Tab>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {1:define}{2: jump list > }| + :sign define^ | + ]]} + + feed('<Tab>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {2:define }{1:jump}{2: list > }| + :sign jump^ | + ]]} + + feed('<Tab>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {2:define jump }{1:list}{2: > }| + :sign list^ | + ]]} + + -- Looped back to the original value + feed('<Tab><Tab><Tab><Tab>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {2:define jump list > }| + :sign ^ | + ]]} + + -- Test that the wild menu is cleared properly + feed('<Space>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + :sign ^ | + ]]} + + -- Test that a different wildchar still works + feed('<Esc>') + command('set wildchar=<Esc>') + feed(':sign <Esc>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {1:define}{2: jump list > }| + :sign define^ | + ]]} + + -- Double-<Esc> is a hard-coded method to escape while wildchar=<Esc>. Make + -- sure clean up is properly done in edge case like this. + feed('<Esc>') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end) + it('C-E to cancel wildmenu completion restore original input', function() feed(':sign <tab>') screen:expect([[ @@ -367,12 +446,12 @@ describe("'wildmenu'", function() } -- Wildcharm? where we are going we aint't no need no wildcharm. - eq(0, meths.get_option'wildcharm') + eq(0, meths.get_option_value('wildcharm', {})) -- Don't mess the defaults yet (neovim is about backwards compatibility) - eq(9, meths.get_option'wildchar') + eq(9, meths.get_option_value('wildchar', {})) -- Lol what is cnoremap? Some say it can define mappings. command 'set wildchar=0' - eq(0, meths.get_option'wildchar') + eq(0, meths.get_option_value('wildchar', {})) command 'cnoremap <f2> <c-z>' feed(':syntax <f2>') @@ -481,9 +560,9 @@ describe('command line completion', function() 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') + meths.set_option_value('wildmenu', true, {}) + meths.set_option_value('wildmode', 'full', {}) + meths.set_option_value('wildoptions', 'pum', {}) feed(':sign unpla<S-Tab>') screen:expect([[ @@ -505,8 +584,8 @@ describe('command line completion', function() 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') + meths.set_option_value('wildmenu', false, {}) + meths.set_option_value('wildmode', 'full', {}) feed(':sign <S-Tab>') screen:expect([[ @@ -519,8 +598,8 @@ describe('command line completion', function() end) it('shows matches with <S-Tab> without wildmenu with wildmode=list', function() - meths.set_option('wildmenu', false) - meths.set_option('wildmode', 'list') + meths.set_option_value('wildmenu', false, {}) + meths.set_option_value('wildmode', 'list', {}) feed(':sign <S-Tab>') screen:expect([[ diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua index ece27ec3ff..78bbcd3a63 100644 --- a/test/functional/ui/winbar_spec.lua +++ b/test/functional/ui/winbar_spec.lua @@ -31,7 +31,7 @@ describe('winbar', function() [10] = {background = Screen.colors.LightGrey, underline = true}, [11] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta}, }) - meths.set_option('winbar', 'Set Up The Bars') + meths.set_option_value('winbar', 'Set Up The Bars', {}) end) it('works', function() @@ -114,6 +114,41 @@ describe('winbar', function() {2:[No Name] [No Name] }| | ]]) + -- 'showcmdloc' "statusline" should not interfere with winbar redrawing #23030 + command('set showcmd showcmdloc=statusline') + feed('<C-W>w') + feed('<C-W>') + screen:expect([[ + {6:Set Up The Bars }│{6:Set Up The Bars }| + │ | + {3:~ }│{3:~ }| + {3:~ }│{2:[No Name] }| + {3:~ }│{5:Set Up The Bars }| + {3:~ }│^ | + {3:~ }│{3:~ }| + {3:~ }│{4:[No Name] ^W }| + {3:~ }│{6:Set Up The Bars }| + {3:~ }│ | + {3:~ }│{3:~ }| + {2:[No Name] [No Name] }| + | + ]]) + feed('w<C-W>W') + screen:expect([[ + {6:Set Up The Bars }│{6:Set Up The Bars }| + │ | + {3:~ }│{3:~ }| + {3:~ }│{2:[No Name] }| + {3:~ }│{5:Set Up The Bars }| + {3:~ }│^ | + {3:~ }│{3:~ }| + {3:~ }│{4:[No Name] }| + {3:~ }│{6:Set Up The Bars }| + {3:~ }│ | + {3:~ }│{3:~ }| + {2:[No Name] [No Name] }| + | + ]]) end) it('works when switching value of \'winbar\'', function() @@ -171,7 +206,7 @@ describe('winbar', function() insert [[ just some random text]] - meths.set_option('winbar', 'Hello, I am a ruler: %l,%c') + meths.set_option_value('winbar', 'Hello, I am a ruler: %l,%c', {}) screen:expect{grid=[[ {1:Hello, I am a ruler: 2,11 }| just some | @@ -415,7 +450,7 @@ describe('winbar', function() | | ]]) - eq(3, meths.get_option('cmdheight')) + eq(3, meths.get_option_value('cmdheight', {})) meths.input_mouse('left', 'drag', '', 1, 11, 10) screen:expect([[ @@ -433,7 +468,7 @@ describe('winbar', function() {2:[No Name] }| | ]]) - eq(1, meths.get_option('cmdheight')) + eq(1, meths.get_option_value('cmdheight', {})) end) it('properly equalizes window height for window-local value', function() @@ -678,3 +713,26 @@ describe('local winbar with tabs', function() ]]} end) end) + +it('winbar works properly when redrawing is postponed #23534', function() + clear({args = { + '-c', 'set laststatus=2 lazyredraw', + '-c', 'setlocal statusline=(statusline) winbar=(winbar)', + '-c', 'call nvim_input(":<Esc>")', + }}) + local screen = Screen.new(60, 6) + screen:attach() + screen:set_default_attr_ids({ + [0] = {foreground = Screen.colors.Blue, bold = true}, + [1] = {bold = true}, + [2] = {bold = true, reverse = true}, + }) + screen:expect([[ + {1:(winbar) }| + ^ | + {0:~ }| + {0:~ }| + {2:(statusline) }| + | + ]]) +end) |