diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-29 21:52:58 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-29 21:52:58 +0000 |
commit | 931bffbda3668ddc609fc1da8f9eb576b170aa52 (patch) | |
tree | d8c1843a95da5ea0bb4acc09f7e37843d9995c86 /test/functional/ui/decorations_spec.lua | |
parent | 142d9041391780ac15b89886a54015fdc5c73995 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-userreg.tar.gz rneovim-userreg.tar.bz2 rneovim-userreg.zip |
Merge remote-tracking branch 'upstream/master' into userreguserreg
Diffstat (limited to 'test/functional/ui/decorations_spec.lua')
-rw-r--r-- | test/functional/ui/decorations_spec.lua | 3296 |
1 files changed, 3082 insertions, 214 deletions
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() |