Files
neovim/test/functional/ui/decorations_spec.lua
T

8714 lines
332 KiB
Lua

local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
local describe, it, before_each, pending = t.describe, t.it, t.before_each, t.pending
local clear = n.clear
local feed = n.feed
local insert = n.insert
local exec_lua = n.exec_lua
local exec = n.exec
local expect_events = t.expect_events
local api = n.api
local fn = n.fn
local command = n.command
local eq = t.eq
local assert_alive = n.assert_alive
local pcall_err = t.pcall_err
--- @return integer
local function setup_provider(code)
return exec_lua([[
local api = vim.api
_G.ns1 = api.nvim_create_namespace "ns1"
]] .. (code or [[
beamtrace = {}
local function on_do(kind, ...)
table.insert(beamtrace, {kind, ...})
end
]]) .. [[
api.nvim_set_decoration_provider(_G.ns1, {
on_start = on_do; on_buf = on_do;
on_win = on_do; on_line = on_do; on_range = on_do;
on_end = on_do; _on_spell_nav = on_do;
})
return _G.ns1
]])
end
local function setup_screen(screen)
screen:set_default_attr_ids {
[1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
[3] = { foreground = Screen.colors.Brown },
[4] = { foreground = Screen.colors.Blue1 },
[5] = { foreground = Screen.colors.Magenta },
[6] = { bold = true, foreground = Screen.colors.Brown },
[7] = { background = Screen.colors.Gray90 },
[8] = { bold = true, reverse = true },
[9] = { reverse = true },
[10] = { italic = true, background = Screen.colors.Magenta },
[11] = { foreground = Screen.colors.Red, background = tonumber('0x005028') },
[12] = { foreground = tonumber('0x990000') },
[13] = { background = Screen.colors.LightBlue },
[14] = { background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue },
[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 },
[19] = { bold = true },
}
end
describe('decorations providers', function()
local screen ---@type test.functional.ui.screen
before_each(function()
clear()
screen = Screen.new(40, 8)
setup_screen(screen)
end)
local mulholland = [[
// just to see if there was an accident
// on Mulholland Drive
try_start();
bufref_T save_buf;
switch_buffer(&save_buf, buf);
posp = getmark(mark, false);
restore_buffer(&save_buf); ]]
local function check_trace(expected)
local actual = exec_lua [[ local b = beamtrace beamtrace = {} return b ]]
expect_events(expected, actual, 'beam trace')
end
it('does not OOM when inserting, rather than appending, to the decoration provider vector', function()
-- Add a dummy decoration provider with a larger ns id than what setup_provider() creates.
-- This forces get_decor_provider() to insert into the providers vector,
-- rather than append, which used to spin in an infinite loop allocating
-- memory until nvim crashed/was killed.
setup_provider([[
local ns2 = api.nvim_create_namespace "ns2"
api.nvim_set_decoration_provider(ns2, {})
]])
assert_alive()
end)
it('leave a trace', function()
insert(mulholland)
setup_provider()
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive |
try_start(); |
bufref_T save_buf; |
switch_buffer(&save_buf, buf); |
posp = getmark(mark, false); |
restore_buffer(&save_buf);^ |
|
]],
}
check_trace {
{ 'start', 4 },
{ 'win', 1000, 1, 0, 6 },
{ 'line', 1000, 1, 0 },
{ 'range', 1000, 1, 0, 0, 1, 0 },
{ 'line', 1000, 1, 1 },
{ 'range', 1000, 1, 1, 0, 2, 0 },
{ 'line', 1000, 1, 2 },
{ 'range', 1000, 1, 2, 0, 3, 0 },
{ 'line', 1000, 1, 3 },
{ 'range', 1000, 1, 3, 0, 4, 0 },
{ 'line', 1000, 1, 4 },
{ 'range', 1000, 1, 4, 0, 5, 0 },
{ 'line', 1000, 1, 5 },
{ 'range', 1000, 1, 5, 0, 6, 0 },
{ 'line', 1000, 1, 6 },
{ 'range', 1000, 1, 6, 0, 7, 0 },
{ 'end', 4 },
}
feed 'iü<esc>'
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive |
try_start(); |
bufref_T save_buf; |
switch_buffer(&save_buf, buf); |
posp = getmark(mark, false); |
restore_buffer(&save_buf);^ü |
|
]],
}
check_trace {
{ 'start', 5 },
{ 'buf', 1, 5 },
{ 'win', 1000, 1, 0, 6 },
{ 'line', 1000, 1, 6 },
{ 'range', 1000, 1, 6, 0, 7, 0 },
{ 'end', 5 },
}
end)
it('can have single provider', function()
insert(mulholland)
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, line,
{ end_line = line, end_col = line+1,
hl_group = hl,
ephemeral = true
})
end
end
]]
screen:expect {
grid = [[
{2:/}/ just to see if there was an accident |
/{2:/} on Mulholland Drive |
tr{2:y}_start(); |
buf{2:r}ef_T save_buf; |
swit{2:c}h_buffer(&save_buf, buf); |
posp {2:=} getmark(mark, false); |
restor{2:e}_buffer(&save_buf);^ |
|
]],
}
end)
it('can indicate spellchecked points', function()
exec [[
set spell
set spelloptions=noplainbuffer
syntax off
]]
insert [[
I am well written text.
i am not capitalized.
I am a speling mistakke.
]]
setup_provider [[
local ns = api.nvim_create_namespace "spell"
beamtrace = {}
local function on_do(kind, ...)
if kind == 'win' or kind == 'spell' then
api.nvim_buf_set_extmark(0, ns, 0, 0, {
end_row = 2,
end_col = 23,
spell = true,
priority = 20,
ephemeral = true
})
end
table.insert(beamtrace, {kind, ...})
end
]]
check_trace {
{ 'start', 5 },
{ 'win', 1000, 1, 0, 3 },
{ 'line', 1000, 1, 0 },
{ 'range', 1000, 1, 0, 0, 1, 0 },
{ 'line', 1000, 1, 1 },
{ 'range', 1000, 1, 1, 0, 2, 0 },
{ 'line', 1000, 1, 2 },
{ 'range', 1000, 1, 2, 0, 3, 0 },
{ 'line', 1000, 1, 3 },
{ 'range', 1000, 1, 3, 0, 4, 0 },
{ 'end', 5 },
}
feed 'gg0'
screen:expect {
grid = [[
^I am well written text. |
{15:i} am not capitalized. |
I am a {16:speling} {16:mistakke}. |
|
{1:~ }|*3
|
]],
}
feed ']s'
check_trace {
{ 'spell', 1000, 1, 1, 0, 1, -1 },
}
screen:expect {
grid = [[
I am well written text. |
{15:^i} am not capitalized. |
I am a {16:speling} {16:mistakke}. |
|
{1:~ }|*3
|
]],
}
feed ']s'
check_trace {
{ 'spell', 1000, 1, 2, 7, 2, -1 },
}
screen:expect {
grid = [[
I am well written text. |
{15:i} am not capitalized. |
I am a {16:^speling} {16:mistakke}. |
|
{1:~ }|*3
|
]],
}
-- spell=false with higher priority does disable spell
local ns = api.nvim_create_namespace 'spell'
local id = api.nvim_buf_set_extmark(0, 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:~ }|*3
|
]],
}
feed ']s'
screen:expect {
grid = [[
I am well written text. |
i am not capitalized. |
I am a ^speling mistakke. |
|
{1:~ }|*3
{17:search hit BOTTOM, continuing at TOP} |
]],
}
command('echo ""')
-- spell=false with lower priority doesn't disable spell
api.nvim_buf_set_extmark(0, 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:~ }|*3
|
]],
}
feed ']s'
screen:expect {
grid = [[
I am well written text. |
{15:i} am not capitalized. |
I am a {16:speling} {16:^mistakke}. |
|
{1:~ }|*3
|
]],
}
end)
it('can predefine highlights', function()
screen:try_resize(40, 16)
insert(mulholland)
exec [[
3
set ft=c
syntax on
set number cursorline
split
]]
local ns1 = setup_provider()
for k, v in pairs {
LineNr = { italic = true, bg = 'Magenta' },
Comment = { fg = '#FF0000', bg = 80 * 256 + 40 },
CursorLine = { link = 'ErrorMsg' },
} do
api.nvim_set_hl(ns1, k, v)
end
screen:expect {
grid = [[
{3: 1 }{4:// just to see if there was an accid}|
{3: }{4:ent} |
{3: 2 }{4:// on Mulholland Drive} |
{6: 3 }{7:^try_start(); }|
{3: 4 }bufref_T save_buf; |
{3: 5 }switch_buffer(&save_buf, buf); |
{3: 6 }posp = getmark(mark, {5:false}); |
{8:[No Name] [+] }|
{3: 2 }{4:// on Mulholland Drive} |
{6: 3 }{7:try_start(); }|
{3: 4 }bufref_T save_buf; |
{3: 5 }switch_buffer(&save_buf, buf); |
{3: 6 }posp = getmark(mark, {5:false}); |
{3: 7 }restore_buffer(&save_buf); |
{9:[No Name] [+] }|
|
]],
}
api.nvim_set_hl_ns(ns1)
screen:expect {
grid = [[
{10: 1 }{11:// just to see if there was an accid}|
{10: }{11:ent} |
{10: 2 }{11:// on Mulholland Drive} |
{6: 3 }{2:^try_start(); }|
{10: 4 }bufref_T save_buf; |
{10: 5 }switch_buffer(&save_buf, buf); |
{10: 6 }posp = getmark(mark, {5:false}); |
{8:[No Name] [+] }|
{10: 2 }{11:// on Mulholland Drive} |
{6: 3 }{2:try_start(); }|
{10: 4 }bufref_T save_buf; |
{10: 5 }switch_buffer(&save_buf, buf); |
{10: 6 }posp = getmark(mark, {5:false}); |
{10: 7 }restore_buffer(&save_buf); |
{9:[No Name] [+] }|
|
]],
}
exec_lua [[
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)
api.nvim_set_hl_ns_fast(win == thewin and _G.ns1 or ns2)
end;
})
]]
screen:expect {
grid = [[
{10: 1 }{11:// just to see if there was an accid}|
{10: }{11:ent} |
{10: 2 }{11:// on Mulholland Drive} |
{6: 3 }{2:^try_start(); }|
{10: 4 }bufref_T save_buf; |
{10: 5 }switch_buffer(&save_buf, buf); |
{10: 6 }posp = getmark(mark, {5:false}); |
{8:[No Name] [+] }|
{3: 2 }{4:// on Mulholland Drive} |
{6: 3 }{7:try_start(); }|
{3: 4 }bufref_T save_buf; |
{3: 5 }switch_buffer(&save_buf, buf); |
{3: 6 }posp = getmark(mark, {5:false}); |
{3: 7 }restore_buffer(&save_buf); |
{9:[No Name] [+] }|
|
]],
}
end)
it('can break an existing link', function()
insert(mulholland)
local ns1 = setup_provider()
exec [[
highlight OriginalGroup guifg='#990000'
highlight link LinkGroup OriginalGroup
]]
api.nvim_buf_set_virtual_text(0, 0, 2, { { '- not red', 'LinkGroup' } }, {})
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive |
try_start(); {12:- not red} |
bufref_T save_buf; |
switch_buffer(&save_buf, buf); |
posp = getmark(mark, false); |
restore_buffer(&save_buf);^ |
|
]],
}
api.nvim_set_hl(ns1, 'LinkGroup', { fg = 'Blue' })
api.nvim_set_hl_ns(ns1)
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive |
try_start(); {4:- not red} |
bufref_T save_buf; |
switch_buffer(&save_buf, buf); |
posp = getmark(mark, false); |
restore_buffer(&save_buf);^ |
|
]],
}
end)
it("with 'default': do not break an existing link", function()
insert(mulholland)
local ns1 = setup_provider()
exec [[
highlight OriginalGroup guifg='#990000'
highlight link LinkGroup OriginalGroup
]]
api.nvim_buf_set_virtual_text(0, 0, 2, { { '- not red', 'LinkGroup' } }, {})
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive |
try_start(); {12:- not red} |
bufref_T save_buf; |
switch_buffer(&save_buf, buf); |
posp = getmark(mark, false); |
restore_buffer(&save_buf);^ |
|
]],
}
api.nvim_set_hl(ns1, 'LinkGroup', { fg = 'Blue', default = true })
api.nvim_set_hl_ns(ns1)
feed 'k'
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive |
try_start(); {12:- not red} |
bufref_T save_buf; |
switch_buffer(&save_buf, buf); |
posp = getmark(mark, false^); |
restore_buffer(&save_buf); |
|
]],
}
end)
it('can have virtual text', function()
insert(mulholland)
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 = {{'+', 'ErrorMsg'}};
virt_text_pos='overlay';
ephemeral = true;
})
end
end
]]
screen:expect {
grid = [[
{2:+}/ just to see if there was an accident |
{2:+}/ on Mulholland Drive |
{2:+}ry_start(); |
{2:+}ufref_T save_buf; |
{2:+}witch_buffer(&save_buf, buf); |
{2:+}osp = getmark(mark, false); |
{2:+}estore_buffer(&save_buf);^ |
|
]],
}
end)
it('can have virtual text of the style: right_align', function()
insert(mulholland)
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='right_align';
ephemeral = true;
})
end
end
]]
screen:expect {
grid = [[
// just to see if there was an acciden+{2: }|
// on Mulholland Drive +{2: }|
try_start(); +{2: }|
bufref_T save_buf; +{2: }|
switch_buffer(&save_buf, buf); +{2: }|
posp = getmark(mark, false); +{2: }|
restore_buffer(&save_buf);^ +{2: }|
|
]],
}
end)
it('can have virtual text of the style: eol_right_align', function()
insert(mulholland)
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 = {{'+'}, {'1234567890', 'ErrorMsg'}};
virt_text_pos='eol_right_align';
ephemeral = true;
})
end
end
]]
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive +{2:1234567890}|
try_start(); +{2:1234567890}|
bufref_T save_buf; +{2:1234567890}|
switch_buffer(&save_buf, buf); +{2:12345678}|
posp = getmark(mark, false); +{2:1234567890}|
restore_buffer(&save_buf);^ +{2:1234567890}|
|
]],
}
end)
it('multiple eol_right_align', function()
insert(mulholland)
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 = {{'11111'}};
virt_text_pos='eol_right_align';
ephemeral = true;
})
api.nvim_buf_set_extmark(0, test_ns, line, 0, {
virt_text = {{'22222'}};
virt_text_pos='eol_right_align';
ephemeral = true;
})
end
end
]]
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive 11111 22222|
try_start(); 11111 22222|
bufref_T save_buf; 11111 22222|
switch_buffer(&save_buf, buf); 11111 222|
posp = getmark(mark, false); 11111 22222|
restore_buffer(&save_buf);^ 11111 22222|
|
]],
}
end)
it('eol_right_align: second text much longer than first', function()
insert('short')
setup_provider [[
local test_ns = api.nvim_create_namespace "test_length_diff"
function on_do(event, ...)
if event == "line" then
local win, buf, line = ...
api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
virt_text = {{'AA', 'Comment'}};
virt_text_pos = 'eol_right_align';
priority = 100;
ephemeral = true;
})
api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
virt_text = {{'BBBBBBBBBBBBBBBBBBBB', 'ErrorMsg'}};
virt_text_pos = 'eol_right_align';
priority = 200;
ephemeral = true;
})
end
end
]]
screen:expect([[
shor^t {4:AA} {2:BBBBBBBBBBBBBBBBBBBB}|
{1:~ }|*6
|
]])
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 = api.nvim_create_namespace "veberod"
function on_do(event, ...)
if event == "line" then
local win, buf, line = ...
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;
ephemeral = true;
})
end
end
end
]]
screen:expect {
grid = [[
// just to see if there was an accident |
// on Mulholland Drive |
try_start(); |
{13:bufref_T save_buf; }|
{13:switch_buffer(&save_buf, buf); }|
posp = getmark(mark, false); |
{13:restore_buffer(&save_buf);^ }|
|
]],
}
end)
it("'hl_eol' extends into 'linebreak'/'breakindent'/'showbreak' gaps", function()
command('set wrap linebreak breakindent breakindentopt=shift:2')
api.nvim_buf_set_lines(0, 0, -1, false, {
' if vim.g.colors_name == "ferricferric" then',
})
local ns = api.nvim_create_namespace('code_bg')
local id = api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = 'DiffAdd', hl_eol = true })
screen:expect([[
{13:^ if vim.g.colors_name == }|
{13: "ferricferric" then }|
{1:~ }|*5
|
]])
-- Extends across the 'showbreak' character too.
command('set showbreak=>')
screen:add_extra_attr_ids({
[100] = { background = Screen.colors.LightBlue },
[101] = { bold = true, foreground = Screen.colors.Blue1, background = Screen.colors.LightBlue },
})
screen:expect([[
{100:^ if vim.g.colors_name == }|
{100: }{101:>}{100:"ferricferric" then }|
{1:~ }|*5
|
]])
-- Without 'hl_eol' the highlight decorates characters, so it leaves the gaps alone, the same
-- way it already leaves the cells past the end of the line alone.
api.nvim_buf_set_extmark(0, ns, 0, 0, { id = id, end_row = 1, hl_group = 'DiffAdd' })
screen:expect([[
{100:^ if vim.g.colors_name == } |
{1:>}{100:"ferricferric" then} |
{1:~ }|*5
|
]])
end)
it('breakindent keeps the highlight after a real linebreak word-push', function()
-- The word pushed down by 'linebreak' resets decor_attr (see listlbr_spec.lua), which must not
-- then leak into 'breakindent's own gap on the row the word lands on.
screen:try_resize(30, 5)
screen:add_extra_attr_ids({ [100] = { background = Screen.colors.LightBlue } })
command('set wrap linebreak breakindent')
local line = ' This is a long indented line of plain text that will wrap nicely.'
api.nvim_buf_set_lines(0, 0, -1, false, { line })
local ns = api.nvim_create_namespace('code_bg2')
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = 'DiffAdd', hl_eol = true })
screen:expect([[
{100:^ This is a long indented }|
{100: line of plain text that }|
{100: will wrap nicely. }|
{1:~ }|
|
]])
end)
it('can create and remove signs when CursorMoved autocommand validates botline #18661', function()
exec_lua([[
local lines = {}
for i = 1, 200 do
lines[i] = 'hello' .. tostring(i)
end
vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
]])
setup_provider([[
local function on_do(kind, winid, bufnr, topline, botline)
if kind == 'win' then
if topline < 100 and botline > 100 then
api.nvim_buf_set_extmark(bufnr, ns1, 99, -1, { sign_text = 'X' })
else
api.nvim_buf_clear_namespace(bufnr, ns1, 0, -1)
end
end
end
]])
command([[autocmd CursorMoved * call line('w$')]])
api.nvim_win_set_cursor(0, { 100, 0 })
screen:expect([[
{14: }hello97 |
{14: }hello98 |
{14: }hello99 |
{14:X }^hello100 |
{14: }hello101 |
{14: }hello102 |
{14: }hello103 |
|
]])
api.nvim_win_set_cursor(0, { 1, 0 })
screen:expect([[
^hello1 |
hello2 |
hello3 |
hello4 |
hello5 |
hello6 |
hello7 |
|
]])
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)
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('on_line is invoked only for buffer lines', function()
insert(mulholland)
command('vnew')
insert(mulholland)
feed('dd')
command('windo diffthis')
exec_lua([[
out_of_bound = false
]])
setup_provider([[
local function on_do(kind, _, bufnr, row)
if kind == 'line' then
if not api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] then
out_of_bound = true
end
end
end
]])
feed('<C-e>')
exec_lua([[
assert(out_of_bound == false)
]])
end)
it('on_range is invoked on all visible characters', function()
clear()
screen = Screen.new(20, 4)
setup_screen(screen)
local function record()
exec_lua(function()
_G.p_min = { math.huge, math.huge }
_G.p_max = { -math.huge, -math.huge }
function _G.pos_gt(a, b)
return a[1] > b[1] or (a[1] == b[1] and a[2] > b[2])
end
function _G.pos_lt(a, b)
return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2])
end
end)
setup_provider [[
local function on_do(kind, _, bufnr, br, bc, er, ec)
if kind == 'range' then
local b = { br, bc }
local e = { er, ec }
if _G.pos_gt(_G.p_min, b) then
_G.p_min = b
end
if _G.pos_lt(_G.p_max, e) then
_G.p_max = e
end
end
end
]]
end
local function check(min, max)
local p_min = exec_lua('return _G.p_min')
assert(
p_min[1] < min[1] or (p_min[1] == min[1] and p_min[2] <= min[2]),
'minimum position ' .. vim.inspect(p_min) .. ' should be before the first char'
)
local p_max = exec_lua('return _G.p_max')
assert(
p_max[1] > max[1] or (p_max[1] == max[1] and p_max[2] >= max[2]),
'maximum position ' .. vim.inspect(p_max) .. ' should be on or after the last char'
)
end
-- Multiple lines.
exec_lua([[
local lines = { ('a'):rep(40), ('b'):rep(40), ('c'):rep(40) }
vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
vim.api.nvim_win_set_cursor(0, { 2, 0 })
]])
record()
screen:expect([[
^bbbbbbbbbbbbbbbbbbbb|
bbbbbbbbbbbbbbbbbbbb|
ccccccccccccccccc{1:@@@}|
|
]])
check({ 1, 0 }, { 2, 21 })
-- One long line.
exec_lua([[
local lines = { ('a'):rep(100) }
vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
vim.api.nvim_win_set_cursor(0, { 1, 70 })
]])
record()
screen:expect([[
{1:<<<}aaaaaaaaaaaaaaaaa|
aaaaaaaaaaaaaaaaaaaa|
aaaaaaaaaa^aaaaaaaaaa|
|
]])
check({ 0, 20 }, { 0, 81 })
-- Multibyte characters.
exec_lua([[
local lines = { ('\195\162'):rep(100) }
vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
vim.api.nvim_win_set_cursor(0, { 1, 70 * 2 })
]])
record()
screen:expect([[
{1:<<<}âââââââââââââââââ|
ââââââââââââââââââââ|
ââââââââââ^ââââââââââ|
|
]])
check({ 0, 20 * 2 }, { 0, 81 * 2 })
-- Tabs.
exec_lua([[
local lines = { 'a' .. ('\t'):rep(100) }
vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
vim.api.nvim_win_set_cursor(0, { 1, 39 })
]])
record()
screen:expect([[
{1:<<<} |
|
^ |
|
]])
check({ 0, 33 }, { 0, 94 })
-- One long line without wrapping.
command('set nowrap')
exec_lua([[
local lines = { ('a'):rep(50) .. ('b'):rep(50) }
vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
vim.api.nvim_win_set_cursor(0, { 1, 50 })
]])
record()
screen:expect([[
aaaaaaaaaa^bbbbbbbbbb|
{1:~ }|*2
|
]])
check({ 0, 40 }, { 0, 60 })
end)
it('can add new providers during redraw #26652', function()
setup_provider [[
local ns = api.nvim_create_namespace('test_no_add')
function on_do(...)
api.nvim_set_decoration_provider(ns, {})
end
]]
n.assert_alive()
end)
it('is not invoked repeatedly in Visual mode with vim.schedule() #20235', function()
exec_lua([[_G.cnt = 0]])
setup_provider([[
function on_do(event, ...)
if event == 'win' then
vim.schedule(function() end)
_G.cnt = _G.cnt + 1
end
end
]])
feed('v')
screen:expect([[
^ |
{1:~ }|*6
{19:-- VISUAL --} |
]])
eq(2, exec_lua([[return _G.cnt]]))
end)
it('can do large changes to the marktree', function()
insert('line1 with a lot of text\nline2 with a lot of text')
setup_provider([[
function on_do(event, _, _, row)
if event == 'win' or (event == 'line' and row == 1) then
vim.api.nvim_buf_clear_namespace(0, ns1, 0, -1)
for i = 0,1 do
for j = 0,23 do
vim.api.nvim_buf_set_extmark(0, ns1, i, j, {hl_group='ErrorMsg', end_col = j+1})
end
end
end
end
]])
-- Doesn't crash when modifying the marktree between line1 and line2
screen:expect([[
{2:line1 with a lot of text} |
{2:line2 with a lot of tex^t} |
{1:~ }|*5
|
]])
end)
it('inline virt_text does not result in wrong cursor column #33153', function()
insert('line1 with a lot of text\nline2 with a lot of text')
setup_provider([[
_G.do_win = false
vim.keymap.set('n', 'f', function()
_G.do_win = true
vim.cmd('redraw!')
end)
vim.o.concealcursor = 'n'
function on_do(event)
if event == 'win' and _G.do_win then
vim.api.nvim_buf_set_extmark(0, ns1, 1, 0, {
virt_text = { { 'virt_text ' } },
virt_text_pos = 'inline'
})
end
end
]])
feed('f')
screen:expect([[
line1 with a lot of text |
virt_text line2 with a lot of tex^t |
{1:~ }|*5
|
]])
end)
it('decor provider is enabled again for next redraw after on_win disabled it', function()
exec_lua(function()
vim.api.nvim_set_decoration_provider(vim.api.nvim_create_namespace(''), {
on_win = function()
return false
end,
on_buf = function()
_G.did_buf = (_G.did_buf or 0) + 1
end,
})
end)
api.nvim_buf_set_lines(0, 0, -1, false, { 'foo' })
screen:expect([[
^foo |
{1:~ }|*6
|
]])
eq(1, exec_lua('return _G.did_buf'))
end)
end)
describe('decoration_providers', function()
it('errors and logs gracefully', function()
local testlog = 'Xtest_decorations_log'
clear({ env = { NVIM_LOG_FILE = testlog } })
local screen = Screen.new(65, 7)
setup_provider([[
function on_do(...)
error "Foo"
end
]])
screen:expect([[
{3: }|
{9:Decoration provider "start" (ns=ns1):} |
{9:Lua: [string "<nvim>"]:4: Foo} |
{9:stack traceback:} |
{9: [C]: in function 'error'} |
{9: [string "<nvim>"]:4: in function <[string "<nvim>"]:3>} |
{6:Press ENTER or type command to continue}^ |
]])
t.assert_log('Error in decoration provider "start" %(ns=ns1%):', testlog, 100)
t.assert_log('Lua: %[string "<nvim>"%]:4: Foo', testlog, 100)
n.check_close()
os.remove(testlog)
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 ---@type test.functional.ui.screen
local ns ---@type integer
before_each(function()
clear()
screen = Screen.new(50, 15)
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] = { foreground = Screen.colors.Brown, bold = true },
[6] = { foreground = Screen.colors.DarkCyan },
[7] = { foreground = Screen.colors.Grey0, background = tonumber('0xff4c4c') },
[8] = { foreground = tonumber('0x180606'), background = tonumber('0xff4c4c') },
[9] = { foreground = tonumber('0xe40c0c'), background = tonumber('0xff4c4c'), bold = true },
[10] = { foreground = tonumber('0xb20000'), background = tonumber('0xff4c4c') },
[11] = { blend = 30, background = Screen.colors.Red1 },
[12] = { foreground = Screen.colors.Brown, blend = 30, background = Screen.colors.Red1, bold = true },
[13] = { foreground = Screen.colors.Fuchsia },
[14] = { background = Screen.colors.Red1, foreground = Screen.colors.Black },
[15] = { background = Screen.colors.Red1, foreground = tonumber('0xb20000') },
[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.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') },
[23] = { foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey },
[24] = { bold = true },
[25] = { background = Screen.colors.LightRed },
[26] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey },
[27] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black },
[28] = { underline = true, foreground = Screen.colors.SlateBlue },
[29] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.LightGrey, underline = true },
[30] = { foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGrey, underline = true },
[31] = { underline = true, foreground = Screen.colors.DarkCyan },
[32] = { underline = true },
[33] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
[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 },
[42] = { undercurl = true, special = Screen.colors.Red },
[43] = { background = Screen.colors.Yellow, undercurl = true, special = Screen.colors.Red },
[44] = { background = Screen.colors.LightMagenta },
[45] = { background = Screen.colors.Red, special = Screen.colors.Red, foreground = Screen.colors.Red },
[46] = { background = Screen.colors.Blue, foreground = Screen.colors.Blue, special = Screen.colors.Red },
[47] = { background = Screen.colors.Green, foreground = Screen.colors.Blue, special = Screen.colors.Red },
}
ns = api.nvim_create_namespace 'test'
end)
it('empty virtual text at eol should not break colorcolumn #17860', function()
insert(example_text)
feed('gg')
command('set colorcolumn=40')
screen:expect([[
^for _,item in ipairs(items) do {25: } |
local text, hl_id_cell, count = unp{25:a}ck(item) |
if hl_id_cell ~= nil then {25: } |
hl_id = hl_id_cell {25: } |
end {25: } |
for _ = 1, (count or 1) do {25: } |
local cell = line[colpos] {25: } |
cell.text = text {25: } |
cell.hl_id = hl_id {25: } |
colpos = colpos+1 {25: } |
end {25: } |
end {25: } |
{1:~ }|*2
|
]])
api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_text = { { '' } }, virt_text_pos = 'eol' })
screen:expect_unchanged()
end)
it('can have virtual text of overlay position', function()
insert(example_text)
feed 'gg'
for i = 1, 9 do
api.nvim_buf_set_extmark(0, ns, i, 0, { virt_text = { { '|', 'LineNr' } }, virt_text_pos = 'overlay' })
if i == 3 or (i >= 6 and i <= 9) then
api.nvim_buf_set_extmark(0, ns, i, 4, { virt_text = { { '|', 'NonText' } }, virt_text_pos = 'overlay' })
end
end
api.nvim_buf_set_extmark(
0,
ns,
9,
10,
{ virt_text = { { 'foo' }, { 'bar', 'MoreMsg' }, { '!!', 'ErrorMsg' } }, virt_text_pos = 'overlay' }
)
-- can "float" beyond end of line
api.nvim_buf_set_extmark(0, ns, 5, 28, { virt_text = { { 'loopy', 'ErrorMsg' } }, virt_text_pos = 'overlay' })
-- bound check: right edge of window
api.nvim_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
api.nvim_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:|} {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 |
end |
{1:~ }|*2
|
]],
}
-- handles broken lines
screen:try_resize(22, 25)
screen:expect {
grid = [[
^for _,item in ipairs(i|
tems) do |
{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 |
end |
{1:~ }|*2
|
]],
}
-- truncating in the middle of a char leaves a space
api.nvim_buf_set_lines(0, 0, 1, true, { 'for _,item in ipairs(items) do -- 古古古' })
api.nvim_buf_set_lines(0, 10, 12, true, { ' end -- ??????????', 'end -- ?古古古古?古古' })
api.nvim_buf_set_extmark(0, ns, 0, 35, { virt_text = { { 'A', 'ErrorMsg' }, { 'AA' } }, virt_text_pos = 'overlay' })
api.nvim_buf_set_extmark(0, ns, 10, 19, { virt_text = { { '口口口', 'ErrorMsg' } }, virt_text_pos = 'overlay' })
api.nvim_buf_set_extmark(0, ns, 11, 21, { virt_text = { { '口口口', 'ErrorMsg' } }, virt_text_pos = 'overlay' })
api.nvim_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:~ }|*2
|
]],
}
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:口口口} |
|
]],
}
api.nvim_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
api.nvim_buf_set_extmark(0, ns, 0, 42 + i, { virt_text = { { tostring(i), 'ErrorMsg' } }, virt_text_pos = 'overlay' })
api.nvim_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{27:babab}ababababababababababababababababababababab|
{1:++}abababababababababababababababababababababababab|
{1:++}ababab |
{24:-- VISUAL --} |
]],
}
feed('o')
screen:expect {
grid = [[
ababababababababababababababababababababab{4:01234567}|
{1:++}{4:89}abababababababababababababababababababa{4:0123456}|
{1:++}{27:ababa}^bababababababababababababababababababababab|
{1:++}abababababababababababababababababababababababab|
{1:++}ababab |
{24:-- VISUAL --} |
]],
}
feed('gk')
screen:expect {
grid = [[
ababababababababababababababababababababab{4:01234567}|
{1:++}{4:89}aba^b{27:ababababababababababababababababababababab}|
{1:++}{27:a}{4:89}babababababababababababababababababababababab|
{1:++}abababababababababababababababababababababababab|
{1:++}ababab |
{24:-- VISUAL --} |
]],
}
feed('o')
screen:expect {
grid = [[
ababababababababababababababababababababab{4:01234567}|
{1:++}{4:89}aba{27: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')
api.nvim_buf_set_lines(0, 0, -1, true, { '-- ' .. ('…'):rep(57) })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { '?????', 'ErrorMsg' } }, virt_text_pos = 'overlay', virt_text_hide = true })
api.nvim_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)
api.nvim_buf_set_lines(0, 0, -1, true, { '\t\tline 1' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Search' } }, virt_text_pos = 'overlay', hl_mode = 'combine' })
api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'BB', 'Search' } }, virt_text_pos = 'overlay', hl_mode = 'combine' })
api.nvim_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()
insert(example_text)
feed 'gg'
command 'set ft=lua'
command 'syntax on'
screen:expect {
grid = [[
{5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
{5:local} text, hl_id_cell, count {5:=} unpack(item) |
{5:if} hl_id_cell {5:~=} {13:nil} {5:then} |
hl_id {5:=} hl_id_cell |
{5:end} |
{5:for} _ {5:=} {13:1}, (count {5:or} {13:1}) {5:do} |
{5:local} cell {5:=} line[colpos] |
cell.text {5:=} text |
cell.hl_id {5:=} hl_id |
colpos {5:=} colpos{5:+}{13:1} |
{5:end} |
{5:end} |
{1:~ }|*2
|
]],
}
command 'hi Blendy guibg=Red blend=30'
command 'hi! Visual guifg=NONE guibg=LightGrey'
api.nvim_buf_set_extmark(
0,
ns,
1,
5,
{ virt_text = { { 'blendy text - here', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'blend' }
)
api.nvim_buf_set_extmark(
0,
ns,
2,
5,
{ virt_text = { { 'combining color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'combine' }
)
api.nvim_buf_set_extmark(
0,
ns,
3,
5,
{ virt_text = { { 'replacing color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'replace' }
)
api.nvim_buf_set_extmark(
0,
ns,
4,
5,
{ virt_text = { { 'blendy text - here', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'blend', virt_text_hide = true }
)
api.nvim_buf_set_extmark(
0,
ns,
5,
5,
{ virt_text = { { 'combining color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'combine', virt_text_hide = true }
)
api.nvim_buf_set_extmark(
0,
ns,
6,
5,
{ virt_text = { { 'replacing color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'replace', virt_text_hide = true }
)
screen:expect {
grid = [[
{5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
{5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count {5:=} unpack(item) |
{5:i}{12:c}{11:ombining col}{12:or} {13:nil} {5:then} |
{11:replacing color}d_cell |
{5:e}{8:bl}{7:endy}{10: }{7:text}{10: }{7:-}{10: }{7:here} |
{5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
{11:replacing color} line[colpos] |
cell.text {5:=} text |
cell.hl_id {5:=} hl_id |
colpos {5:=} colpos{5:+}{13:1} |
{5:end} |
{5:end} |
{1:~ }|*2
|
]],
}
feed 'V5G'
screen:expect {
grid = [[
{17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
{18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} |
{18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} |
{18: }{11:replacing color}{18:d_cell} |
{18: }{5:^e}{17:nd} |
{5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
{11:replacing color} line[colpos] |
cell.text {5:=} text |
cell.hl_id {5:=} hl_id |
colpos {5:=} colpos{5:+}{13:1} |
{5:end} |
{5:end} |
{1:~ }|*2
{24:-- VISUAL LINE --} |
]],
}
feed 'jj'
screen:expect {
grid = [[
{17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
{18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} |
{18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} |
{18: }{11:replacing color}{18:d_cell} |
{18: }{17:end} |
{18: }{17:for}{18: _ }{17:=}{18: }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} |
{18: }^ {18: }{17:local}{18: cell }{17:=}{18: line[colpos]} |
cell.text {5:=} text |
cell.hl_id {5:=} hl_id |
colpos {5:=} colpos{5:+}{13:1} |
{5:end} |
{5:end} |
{1:~ }|*2
{24:-- VISUAL LINE --} |
]],
}
end)
it('can have virtual text of right_align and fixed win_col position', function()
insert(example_text)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'Very', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' })
api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'VERY', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
api.nvim_buf_set_extmark(0, ns, 2, 10, { virt_text = { { 'Much', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' })
api.nvim_buf_set_extmark(0, ns, 2, 10, { virt_text = { { 'MUCH', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
api.nvim_buf_set_extmark(0, ns, 3, 14, { virt_text = { { 'Error', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' })
api.nvim_buf_set_extmark(0, ns, 3, 14, { virt_text = { { 'ERROR', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
api.nvim_buf_set_extmark(0, ns, 7, 21, { virt_text = { { '-', 'NonText' } }, virt_text_win_col = 4, hl_mode = 'blend' })
api.nvim_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
api.nvim_buf_set_extmark(0, ns, 8, 0, { virt_text = { { '' } }, virt_text_win_col = 14, hl_mode = 'blend' })
api.nvim_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(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.hl_id = hl_id |
colpos = colpos+1 |
end |
end |
{1:~ }|*2
|
]],
}
feed '3G12|i<cr><esc>'
screen:expect {
grid = [[
for _,item in ipairs(items) do |
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} {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 |
{1:~ }|
|
]],
}
feed 'u:<cr>'
screen:expect {
grid = [[
for _,item in ipairs(items) do |
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.hl_id = hl_id |
colpos = colpos+1 |
end |
end |
{1:~ }|*2
: |
]],
}
feed '8|i<cr><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}|
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.hl_id = hl_id |
colpos = colpos+1 |
end |
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 |
|
]],
}
api.nvim_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')
api.nvim_buf_set_lines(0, 0, -1, false, { string.rep('a', 50) })
screen:expect {
grid = [[
^aaaaaaaaaaaaaaaaaaaaaaaaa│ |
aaaaaaaaaaaaaaaaaaaaaaaaa│{1:~ }|
{1:~ }│{1:~ }|*2
{41:[No Name] [+] }{40:[No Name] }|
|
]],
}
local extmark_opts = { virt_text_win_col = 35, virt_text = { { ' ', 'Comment' } } }
api.nvim_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.
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Underlined' } }, hl_mode = 'combine', virt_text_pos = 'overlay' })
api.nvim_buf_set_extmark(0, ns, 0, 5, { virt_text = { { 'BB', 'Underlined' } }, hl_mode = 'combine', virt_text_win_col = 10 })
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Underlined' } }, virt_text_pos = 'overlay' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB', 'Underlined' } }, virt_text_win_col = 10 })
api.nvim_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') },
[3] = { background = tonumber('0x123456'), foreground = tonumber('0xcccccc') },
[4] = { background = tonumber('0x234567'), foreground = tonumber('0xbbbbbb') },
[5] = { background = tonumber('0x234567'), foreground = tonumber('0xcccccc') },
[6] = { bold = true, foreground = tonumber('0xcccccc'), background = tonumber('0x234567') },
}
exec [[
hi BgOne guibg=#123456
hi BgTwo guibg=#234567
hi FgEin guifg=#bbbbbb
hi FgZwei guifg=#cccccc
hi VeryBold gui=bold
]]
insert('##')
local vt = {
{ 'a', { 'BgOne', 'FgEin' } },
{ 'b', { 'BgOne', 'FgZwei' } },
{ 'c', { 'BgTwo', 'FgEin' } },
{ 'd', { 'BgTwo', 'FgZwei' } },
{ 'X', { 'BgTwo', 'FgZwei', 'VeryBold' } },
}
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'eol' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'right_align' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'inline' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { vt, vt } })
screen:expect {
grid = [[
{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
{1:~ }|
|
]],
}
end)
it('does not crash when deleting a cleared buffer #15212', function()
exec_lua [[
ns = vim.api.nvim_create_namespace("myplugin")
vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {virt_text = {{"a"}}, end_col = 0})
]]
screen:expect {
grid = [[
^ a |
{1:~ }|*13
|
]],
}
exec_lua [[
vim.api.nvim_buf_clear_namespace(0, ns, 0, -1)
vim.cmd("bdelete")
]]
screen:expect {
grid = [[
^ |
{1:~ }|*13
|
]],
}
assert_alive()
end)
it('conceal with conceal char #19007', function()
screen:try_resize(50, 5)
insert('foo\n')
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 0, end_row = 2, conceal = 'X' })
command('set conceallevel=2')
screen:expect([[
{26:X} |
^ |
{1:~ }|*2
|
]])
command('set conceallevel=1')
screen:expect_unchanged()
eq('conceal char must be printable', pcall_err(api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 0, end_row = 2, conceal = 'ẍ̲' })
command('set conceallevel=2')
screen:expect([[
{26:ẍ̲} |
^ |
{1:~ }|*2
|
]])
command('set conceallevel=1')
screen:expect_unchanged()
-- this is rare, but could happen. Save at least the first codepoint
api.nvim__invalidate_glyph_cache()
screen:expect {
grid = [[
{26:x} |
^ |
{1:~ }|*2
|
]],
}
end)
it('conceal without conceal char #24782', function()
screen:try_resize(50, 5)
insert('foobar\n')
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, conceal = '' })
command('set listchars=conceal:?')
command('let &conceallevel=1')
screen:expect([[
{26:?}bar |
^ |
{1:~ }|*2
|
]])
command('let &conceallevel=2')
screen:expect([[
bar |
^ |
{1:~ }|*2
|
]])
end)
it('conceal works just before truncated double-width char #21486', function()
screen:try_resize(40, 4)
api.nvim_buf_set_lines(0, 0, -1, true, { '', ('a'):rep(37) .. '<>古' })
api.nvim_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('redraws properly when adding/removing conceal on non-current line', function()
screen:try_resize(50, 5)
api.nvim_buf_set_lines(0, 0, -1, true, { 'abcd', 'efgh', 'ijkl', 'mnop' })
command('setlocal conceallevel=2')
screen:expect {
grid = [[
^abcd |
efgh |
ijkl |
mnop |
|
]],
}
api.nvim_buf_set_extmark(0, ns, 2, 1, { end_col = 3, conceal = '' })
screen:expect {
grid = [[
^abcd |
efgh |
il |
mnop |
|
]],
}
api.nvim_buf_clear_namespace(0, ns, 0, -1)
screen:expect {
grid = [[
^abcd |
efgh |
ijkl |
mnop |
|
]],
}
end)
it('avoids redraw issue #20651', function()
exec_lua [[
vim.cmd.normal'10oXXX'
vim.cmd.normal'gg'
local ns = vim.api.nvim_create_namespace('ns')
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_open_win(bufnr, false, { relative = 'win', height = 1, width = 1, row = 0, col = 0 })
vim.api.nvim_create_autocmd('CursorMoved', { callback = function()
local row = vim.api.nvim_win_get_cursor(0)[1] - 1
vim.api.nvim_buf_set_extmark(0, ns, row, 0, { id = 1 })
vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {})
vim.schedule(function()
vim.api.nvim_buf_set_extmark(0, ns, row, 0, {
id = 1,
virt_text = {{'HELLO', 'Normal'}},
})
end)
end
})
]]
for _ = 1, 3 do
vim.uv.sleep(10)
feed 'j'
end
screen:expect {
grid = [[
{44: } |
XXX |*2
^XXX HELLO |
XXX |*7
{1:~ }|*3
|
]],
}
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 },
})
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 20 })
api.nvim_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:~ }|
|
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 20 })
api.nvim_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:~ }|
|
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 30 })
api.nvim_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:~ }|
|
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 30 })
api.nvim_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
api.nvim_buf_clear_namespace(0, ns, 0, -1)
screen:expect([[
aaabbbaa^a |
{0:~ }|
|
]])
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 25 + d })
api.nvim_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
api.nvim_buf_clear_namespace(0, ns, 0, -1)
screen:expect([[
aaabbbaa^a |
{0:~ }|
|
]])
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 25 + d })
api.nvim_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')
command('hi default MyMark guibg=LightGrey')
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, hl_mode = 'combine', hl_group = 'MyMark' })
command('hi default MyLine gui=underline')
command('sign define CurrentLine linehl=MyLine')
fn.sign_place(6, 'Test', 'CurrentLine', '', { lnum = 1 })
screen:expect {
grid = [[
{30:^fun}{31:ction}{32: Func() }|
{6:end} |
|
]],
}
end)
it('highlight can combine multiple groups', function()
screen:try_resize(50, 3)
command('hi Group1 guibg=Red guifg=Red guisp=Red')
command('hi Group2 guibg=Blue guifg=Blue')
command('hi Group3 guibg=Green')
insert([[example text]])
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = {} })
screen:expect([[
example tex^t |
{1:~ }|
|
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1' } })
screen:expect([[
{45:example tex^t} |
{1:~ }|
|
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2' } })
screen:expect([[
{46:example tex^t} |
{1:~ }|
|
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2', 'Group3' }, hl_eol = true })
screen:expect([[
{47:example tex^t }|
{1:~ }|
|
]])
eq(
"Invalid 'hl_group': 'hl_group item'",
pcall_err(api.nvim_buf_set_extmark, 0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2', { 'fail' } }, hl_eol = true })
)
end)
it('highlight works after TAB with sidescroll #14201', function()
screen:try_resize(50, 3)
command('set nowrap')
api.nvim_buf_set_lines(0, 0, -1, true, { '\tword word word word' })
api.nvim_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)
api.nvim_buf_set_lines(0, 0, -1, true, { 'this is the\ttab' })
api.nvim_buf_set_extmark(0, ns, 0, 11, { end_col = 15, hl_group = 'ErrorMsg' })
screen:expect {
grid = [[
^this is the{4: tab} |
{1:~ }|
|
]],
}
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_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)
api.nvim_buf_set_lines(0, 0, -1, true, { '\t-- match1', ' -- match2' })
fn.matchadd('NonText', 'match')
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, end_col = 0, hl_group = 'Search' })
api.nvim_buf_set_extmark(0, ns, 1, 0, { end_row = 2, end_col = 0, hl_group = 'Search' })
screen:expect {
grid = [[
{34: ^ -- }{35:match}{34:1} |
{34: -- }{35:match}{34:2} |
|
]],
}
end)
it('highlight applies to a full TAB in visual block mode', function()
screen:try_resize(50, 8)
command('hi! Visual guifg=NONE guibg=LightGrey')
api.nvim_buf_set_lines(0, 0, -1, true, { 'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 5, end_col = 0, hl_group = 'Underlined' })
screen:expect([[
{28:^asdf} |
{28: asdf} |*3
{28:asdf} |
{1:~ }|*2
|
]])
feed('<C-V>Gll')
screen:expect([[
{29:asd}{28:f} |
{29: }{28: asdf} |*3
{29:as}{28:^df} |
{1:~ }|*2
{24:-- VISUAL BLOCK --} |
]])
end)
it('highlight works properly with multibyte text and spell #26771', function()
insert('口口\n')
screen:try_resize(50, 3)
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, hl_group = 'Search' })
screen:expect([[
{34:口}口 |
^ |
|
]])
command('setlocal spell')
screen:expect([[
{43:口}{42:口} |
^ |
|
]])
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
api.nvim_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:~ }|*2
|
]],
}
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:~ }|*7
|
]],
}
api.nvim_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:~ }|*7
|
]],
}
end)
local function with_undo_restore(val)
screen:try_resize(50, 5)
insert(example_text)
feed 'gg'
api.nvim_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 |
|
]],
}
api.nvim_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 = ns,
priority = 4096,
right_gravity = true,
},
},
}, api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'EOL', 'Underlined' } } })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'right_align', 'Underlined' } }, virt_text_pos = 'right_align' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'win_col', 'Underlined' } }, virt_text_win_col = 20 })
api.nvim_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('virtual text overwrites double-width char properly', function()
screen:try_resize(50, 3)
insert('abcdefghij口klmnopqrstu口vwx口yz')
feed('0')
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { '!!!!!', 'Underlined' } }, virt_text_win_col = 11 })
screen:expect {
grid = [[
^abcdefghij {28:!!!!!}opqrstu口vwx口yz |
{1:~ }|
|
]],
}
feed('8x')
screen:expect {
grid = [[
^ij口klmnopq{28:!!!!!} vwx口yz |
{1:~ }|
|
]],
}
feed('3l5x')
screen:expect {
grid = [[
ij口^pqrstu {28:!!!!!} yz |
{1:~ }|
|
]],
}
feed('5x')
screen:expect {
grid = [[
ij口^u口vwx {28:!!!!!} |
{1:~ }|
|
]],
}
end)
it('virtual text blending space does not overwrite double-width char', function()
screen:try_resize(50, 3)
insert('abcdefghij口klmnopqrstu口vwx口yz')
feed('0')
command('hi Blendy guibg=Red blend=30')
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { ' ! ! ', 'Blendy' } }, virt_text_win_col = 8, hl_mode = 'blend' })
screen:expect {
grid = [[
^abcdefgh{10:i}{7:!}{10:口}{7:!}{10:l}mnopqrstu口vwx口yz |
{1:~ }|
|
]],
}
feed('x')
screen:expect {
grid = [[
^bcdefghi{10:j}{7:!}{10: k}{7:!}{10:m}nopqrstu口vwx口yz |
{1:~ }|
|
]],
}
feed('x')
screen:expect {
grid = [[
^cdefghij{10: }{7:!}{10:kl}{7:!}{10:n}opqrstu口vwx口yz |
{1:~ }|
|
]],
}
feed('x')
screen:expect {
grid = [[
^defghij口{7:!}{10:lm}{7:!}{10:o}pqrstu口vwx口yz |
{1:~ }|
|
]],
}
feed('7x')
screen:expect {
grid = [[
^口klmnop{10:q}{7:!}{10:st}{7:!}{10:口}vwx口yz |
{1:~ }|
|
]],
}
end)
it('virtual text 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: ~}|
|
]],
}
api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'overlayed', 'Underlined' } }, virt_text_pos = 'overlay' })
api.nvim_buf_set_extmark(0, ns, 0, 14, { virt_text = { { '古', 'Underlined' } }, virt_text_pos = 'overlay' })
api.nvim_buf_set_extmark(0, ns, 0, 20, { virt_text = { { '\t', 'Underlined' } }, virt_text_pos = 'overlay' })
api.nvim_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('virtual text is drawn correctly after delete and undo #27368', function()
insert('aaa\nbbb\nccc\nddd\neee')
command('vsplit')
api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'EOL' } } })
feed('3gg')
screen:expect {
grid = [[
aaa │aaa |
bbb │bbb |
^ccc EOL │ccc EOL |
ddd │ddd |
eee │eee |
{1:~ }│{1:~ }|*8
{41:[No Name] [+] }{40:[No Name] [+] }|
|
]],
}
feed('dd')
screen:expect {
grid = [[
aaa │aaa |
bbb │bbb |
^ddd EOL │ddd EOL |
eee │eee |
{1:~ }│{1:~ }|*9
{41:[No Name] [+] }{40:[No Name] [+] }|
|
]],
}
command('silent undo')
screen:expect {
grid = [[
aaa │aaa |
bbb │bbb |
^ccc EOL │ccc EOL |
ddd │ddd |
eee │eee |
{1:~ }│{1:~ }|*8
{41:[No Name] [+] }{40:[No Name] [+] }|
|
]],
}
end)
it('virtual text does not crash with blend, conceal and wrap #27836', function()
screen:try_resize(50, 3)
insert(('a'):rep(45) .. '|hidden|' .. ('b'):rep(45))
command('syntax match test /|hidden|/ conceal')
command('set conceallevel=2 concealcursor=n')
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'FOO' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
screen:expect {
grid = [[
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa FOO|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b |
|
]],
}
end)
it('works with both hl_group and sign_hl_group', function()
screen:try_resize(50, 3)
screen:add_extra_attr_ids({
[100] = { background = Screen.colors.WebGray, foreground = Screen.colors.Blue, bold = true },
})
insert('abcdefghijklmn')
api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S', sign_hl_group = 'NonText', hl_group = 'Error', end_col = 14 })
screen:expect([[
{100:S }{9:abcdefghijklm^n} |
{1:~ }|
|
]])
end)
it('virt_text_repeat_linebreak repeats virtual text on wrapped lines', function()
screen:try_resize(40, 5)
api.nvim_set_option_value('breakindent', true, {})
insert(example_text)
api.nvim_buf_set_extmark(
0,
ns,
1,
0,
{ virt_text = { { '│', 'NonText' } }, virt_text_pos = 'overlay', virt_text_repeat_linebreak = true }
)
api.nvim_buf_set_extmark(
0,
ns,
1,
3,
{ virt_text = { { '│', 'NonText' } }, virt_text_pos = 'overlay', virt_text_repeat_linebreak = true }
)
command('norm gg')
screen:expect {
grid = [[
^for _,item in ipairs(items) do |
{1:│} {1:│}local text, hl_id_cell, count = unpa|
{1:│} {1:│}ck(item) |
if hl_id_cell ~= nil then |
|
]],
}
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(
0,
ns,
1,
0,
{ virt_text = { { '│', 'NonText' } }, virt_text_repeat_linebreak = true, virt_text_win_col = 0 }
)
api.nvim_buf_set_extmark(
0,
ns,
1,
0,
{ virt_text = { { '│', 'NonText' } }, virt_text_repeat_linebreak = true, virt_text_win_col = 2 }
)
screen:expect {
grid = [[
^for _,item in ipairs(items) do |
{1:│} {1:│} local text, hl_id_cell, count = unpa|
{1:│} {1:│} ck(item) |
if hl_id_cell ~= nil then |
|
]],
}
end)
it('supports URLs', function()
insert(example_text)
local url1 = 'https://example.com'
local url2 = 'http://127.0.0.1'
screen:add_extra_attr_ids {
u = { url = url1 },
uh = { url = url2, background = Screen.colors.Yellow },
}
api.nvim_buf_set_extmark(0, ns, 1, 4, {
end_col = 14,
url = url1,
})
api.nvim_buf_set_extmark(0, ns, 2, 4, {
end_col = 17,
hl_group = 'Search',
url = url2,
})
screen:expect([[
for _,item in ipairs(items) do |
{u:local text}, hl_id_cell, count = unpack(item) |
{uh: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 |
en^d |
{1:~ }|*2
|
]])
end)
it('can replace marks in place with different decorations #27211', function()
local mark = api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'foo', 'ErrorMsg' } } } })
screen:expect {
grid = [[
^ |
{4:foo} |
{1:~ }|*12
|
]],
}
api.nvim_buf_set_extmark(0, ns, 0, 0, {
id = mark,
virt_text = { { 'testing', 'NonText' } },
virt_text_pos = 'inline',
})
screen:expect {
grid = [[
{1:^testing} |
{1:~ }|*13
|
]],
}
api.nvim_buf_del_extmark(0, ns, mark)
screen:expect {
grid = [[
^ |
{1:~ }|*13
|
]],
}
n.assert_alive()
end)
it('priority ordering of overlay or win_col virtual text at same position', function()
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'A' } }, virt_text_pos = 'overlay', priority = 100 })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'A' } }, virt_text_win_col = 30, priority = 100 })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB' } }, virt_text_pos = 'overlay', priority = 90 })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB' } }, virt_text_win_col = 30, priority = 90 })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'CCC' } }, virt_text_pos = 'overlay', priority = 80 })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'CCC' } }, virt_text_win_col = 30, priority = 80 })
screen:expect([[
^ABC ABC |
{1:~ }|*13
|
]])
end)
it('priority ordering of inline and non-inline virtual text at same char', function()
insert(('?'):rep(40) .. ('!'):rep(30))
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'A' } }, virt_text_pos = 'overlay', priority = 10 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'a' } }, virt_text_win_col = 15, priority = 10 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'BBBB' } }, virt_text_pos = 'inline', priority = 15 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'C' } }, virt_text_pos = 'overlay', priority = 20 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'c' } }, virt_text_win_col = 17, priority = 20 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'DDDD' } }, virt_text_pos = 'inline', priority = 25 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'E' } }, virt_text_pos = 'overlay', priority = 30 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'e' } }, virt_text_win_col = 19, priority = 30 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'FFFF' } }, virt_text_pos = 'inline', priority = 35 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'G' } }, virt_text_pos = 'overlay', priority = 40 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'g' } }, virt_text_win_col = 21, priority = 40 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'HHHH' } }, virt_text_pos = 'inline', priority = 45 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'I' } }, virt_text_pos = 'overlay', priority = 50 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'i' } }, virt_text_win_col = 23, priority = 50 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'JJJJ' } }, virt_text_pos = 'inline', priority = 55 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'K' } }, virt_text_pos = 'overlay', priority = 60 })
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'k' } }, virt_text_win_col = 25, priority = 60 })
screen:expect([[
???????????????a?c?e????????????????????ABBBCDDDEF|
FFGHHHIJJJK!!!!!!!!!!g!i!k!!!!!!!!!!!!!^! |
{1:~ }|*12
|
]])
feed('02x$')
screen:expect([[
???????????????a?c?e??????????????????ABBBCDDDEFFF|
GHHHIJJJK!!!!!!!!!!!!g!i!k!!!!!!!!!!!^! |
{1:~ }|*12
|
]])
feed('02x$')
screen:expect([[
???????????????a?c?e?g??????????????ABBBCDDDEFFFGH|
HHIJJJK!!!!!!!!!!!!!!!!i!k!!!!!!!!!^! |
{1:~ }|*12
|
]])
feed('02x$')
screen:expect([[
???????????????a?c?e?g????????????ABBBCDDDEFFFGHHH|
IJJJK!!!!!!!!!!!!!!!!!!i!k!!!!!!!^! |
{1:~ }|*12
|
]])
command('set nowrap')
feed('0')
screen:expect([[
^???????????????a?c?e?g?i?k????????ABBBCDDDEFFFGHHH|
{1:~ }|*13
|
]])
feed('2x')
screen:expect([[
^???????????????a?c?e?g?i?k??????ABBBCDDDEFFFGHHHIJ|
{1:~ }|*13
|
]])
feed('2x')
screen:expect([[
^???????????????a?c?e?g?i?k????ABBBCDDDEFFFGHHHIJJJ|
{1:~ }|*13
|
]])
feed('2x')
screen:expect([[
^???????????????a?c?e?g?i?k??ABBBCDDDEFFFGHHHIJJJK!|
{1:~ }|*13
|
]])
end)
it('conceal_lines', function()
insert(example_text)
exec('set number conceallevel=3')
feed('ggj')
local not_concealed = {
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 2 }^ local text, hl_id_cell, count = unpack(ite|
{2: }m) |
{2: 3 } if hl_id_cell ~= nil then |
{2: 4 } hl_id = hl_id_cell |
{2: 5 } end |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|
|
]],
}
screen:expect(not_concealed)
api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' })
screen:expect_unchanged()
feed('j')
local concealed = {
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 }^ if hl_id_cell ~= nil then |
{2: 4 } hl_id = hl_id_cell |
{2: 5 } end |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*3
|
]],
}
screen:expect(concealed)
feed('k')
screen:expect(not_concealed)
exec('set concealcursor=n')
screen:expect(concealed)
api.nvim_buf_set_extmark(0, ns, 3, 0, { conceal_lines = '' })
screen:expect({
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 }^ if hl_id_cell ~= nil then |
{2: 5 } end |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*4
|
]],
})
feed('kjj')
screen:expect_unchanged()
api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' })
feed('kjjjC')
screen:expect({
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 } if hl_id_cell ~= nil then |
{2: 5 }^ |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*4
{24:-- INSERT --} |
]],
})
feed('<esc>')
screen:expect({
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 } if hl_id_cell ~= nil then |
{2: 6 }^ for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*5
|
]],
})
feed('kji')
screen:expect({
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 } if hl_id_cell ~= nil then |
{2: 5 }^ |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*4
{24:-- INSERT --} |
]],
})
feed('conceal text')
screen:expect({
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 } if hl_id_cell ~= nil then |
{2: 5 }conceal text^ |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*4
{24:-- INSERT --} |
]],
})
feed('<esc>')
screen:expect({
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 } if hl_id_cell ~= nil then |
{2: 6 } for _ =^ 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*5
|
]],
})
feed('ggzfj')
screen:expect({
grid = [[
{2: 1 }{33:^+-- 2 lines: for _,item in ipairs(items) do··}|
{2: 3 } if hl_id_cell ~= nil then |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*5
|
]],
})
feed('j')
screen:expect({
grid = [[
{2: 1 }{33:+-- 2 lines: for _,item in ipairs(items) do··}|
{2: 3 }^ if hl_id_cell ~= nil then |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*5
|
]],
})
feed('ggzdjzfj')
screen:expect({
grid = [[
{2: 1 }for _,item in ipairs(items) do |
{2: 6 }^ for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*6
|
]],
})
feed('jj')
screen:expect({
grid = [[
{2: 1 }^for _,item in ipairs(items) do |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*6
|
]],
})
-- Below virtual line belonging to line above concealed line is drawn.
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'line 1 below' } } } })
-- Above virtual line belonging to concealed line isn't.
api.nvim_buf_set_extmark(0, ns, 1, 0, {
virt_lines = { { { 'line 2 above' } } },
virt_lines_above = true,
})
screen:expect([[
{2: 1 }for _,item in ipairs(items) do |
{2: }line 1 below |
{2: 6 }^ for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*5
|
]])
-- w_lines.wl_lastlnum values are valid
command('set relativenumber concealcursor=')
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' })
api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' })
feed('zE')
screen:expect([[
{2: 4 }for _,item in ipairs(items) do |
{2: 2 } if hl_id_cell ~= nil then |
{2: 1 } hl_id = hl_id_cell |
{2:5 }^conceal text |
{2: 1 } for _ = 1, (count or 1) do |
{2: 2 } local cell = line[colpos] |
{2: 3 } cell.text = text |
{2: 4 } cell.hl_id = hl_id |
{2: 5 } colpos = colpos+1 |
{2: 6 } end |
{2: 7 }end |
{1:~ }|*3
|
]])
feed('jj')
screen:expect([[
{2: 6 }for _,item in ipairs(items) do |
{2: 4 } if hl_id_cell ~= nil then |
{2: 3 } hl_id = hl_id_cell |
{2: 1 } for _ = 1, (count or 1) do |
{2:7 }^ local cell = line[colpos] |
{2: 1 } cell.text = text |
{2: 2 } cell.hl_id = hl_id |
{2: 3 } colpos = colpos+1 |
{2: 4 } end |
{2: 5 }end |
{1:~ }|*4
|
]])
-- Correct relativenumber for line below concealed line #33694
feed('4Gk')
screen:expect([[
{2: 2 }for _,item in ipairs(items) do |
{2:3 } if h^l_id_cell ~= nil then |
{2: 1 } hl_id = hl_id_cell |
{2: 3 } for _ = 1, (count or 1) do |
{2: 4 } local cell = line[colpos] |
{2: 5 } cell.text = text |
{2: 6 } cell.hl_id = hl_id |
{2: 7 } colpos = colpos+1 |
{2: 8 } end |
{2: 9 }end |
{1:~ }|*4
|
]])
-- Also with above virtual line #32744
command('set nornu')
api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'virt_below 4' } } } })
feed('6G')
screen:expect([[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 } if hl_id_cell ~= nil then |
{2: 4 } hl_id = hl_id_cell |
{2: }virt_below 4 |
{2: 6 } ^for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*3
|
]])
feed('j')
screen:expect([[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 } if hl_id_cell ~= nil then |
{2: 4 } hl_id = hl_id_cell |
{2: }virt_below 4 |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } ^ local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*3
|
]])
-- Even when virtual line is added as line is concealed #32762
feed('5G')
api.nvim_buf_clear_namespace(0, ns, 3, 4)
feed('j')
api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'virt_below 4' } } } })
screen:expect([[
{2: 1 }for _,item in ipairs(items) do |
{2: 3 } if hl_id_cell ~= nil then |
{2: 4 } hl_id = hl_id_cell |
{2: }virt_below 4 |
{2: 6 }^ for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|*3
|
]])
-- No scrolling for concealed topline #33033
api.nvim_buf_clear_namespace(0, ns, 0, -1)
api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_lines_above = true, virt_lines = { { { 'virt_above 2' } } } })
api.nvim_buf_set_extmark(0, ns, 0, 0, { conceal_lines = '' })
feed('ggjj')
screen:expect([[
{2: }virt_above 2 |
{2: 2 } local text, hl_id_cell, count = unpack(ite|
{2: }m) |
{2: 3 }^ if hl_id_cell ~= nil then |
{2: 4 } hl_id = hl_id_cell |
{2: 5 }conceal text |
{2: 6 } for _ = 1, (count or 1) do |
{2: 7 } local cell = line[colpos] |
{2: 8 } cell.text = text |
{2: 9 } cell.hl_id = hl_id |
{2: 10 } colpos = colpos+1 |
{2: 11 } end |
{2: 12 }end |
{1:~ }|
|
]])
-- No asymmetric topline for <C-E><C-Y> #33182
feed('4<C-E>')
exec('set concealcursor=n')
api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' })
eq(5, n.fn.line('w0'))
feed('<C-E><C-Y>')
eq(5, n.fn.line('w0'))
end)
it('conceal_lines not checking on invalid row #36057', function()
exec_lua(function()
vim.fn.setline(1, { 'foo', 'bar', 'baz' })
vim.api.nvim_command('set conceallevel=3 scrolloff=3')
vim.api.nvim_open_win(0, true, { width = 1, height = 1, relative = 'editor', row = 0, col = 0 })
vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' })
vim.api.nvim__redraw({ flush = true })
end)
n.assert_alive()
end)
it('redraws the line from which a left gravity mark has moved #27369', function()
fn.setline(1, { 'aaa', 'bbb', 'ccc', 'ddd' })
api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'foo' } }, right_gravity = false })
feed('yyp')
screen:expect([[
aaa |
^aaa foo |
bbb |
ccc |
ddd |
{1:~ }|*9
|
]])
end)
it('redraws extmark that starts and ends outside the screen', function()
local lines = vim.split(('1'):rep(20), '', { plain = true })
api.nvim_buf_set_lines(0, 0, -1, true, lines)
api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'ErrorMsg', end_row = 19, end_col = 0 })
screen:expect({
grid = [[
{4:^1} |
{4:1} |*13
|
]],
})
feed('<C-e>')
-- Newly visible line should also have the highlight.
screen:expect({
grid = [[
{4:^1} |
{4:1} |*13
|
]],
})
end)
it('line("w$", win) considers conceal_lines', function()
api.nvim_buf_set_lines(0, 0, -1, true, { 'line 1', 'line 2', 'line 3' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { conceal_lines = '' }) -- conceal line 1
local win = exec_lua(function()
local provider_ns = vim.api.nvim_create_namespace('test_f_line')
_G.line_w_dollar = {}
vim.api.nvim_set_decoration_provider(provider_ns, {
on_start = function()
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
table.insert(_G.line_w_dollar, { win, vim.fn.line('w$', win) })
end
end,
})
local win = vim.api.nvim_open_win(0, false, {
relative = 'editor',
width = 20,
height = 1,
row = 0,
col = 0,
border = 'single',
})
vim.api.nvim_set_option_value('conceallevel', 2, { scope = 'local', win = win })
return win
end)
local line_w_dollar = exec_lua('return _G.line_w_dollar')
for _, win_line in ipairs(line_w_dollar) do
if win_line[1] == win then
eq(2, win_line[2])
end
end
end)
end)
describe('decorations: inline virtual text', function()
local screen ---@type test.functional.ui.screen
local ns ---@type integer
before_each(function()
clear()
screen = Screen.new(50, 3)
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, foreground = Screen.colors.Black },
[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 },
[22] = { background = Screen.colors.Gray90 },
[23] = { background = Screen.colors.Gray90, foreground = Screen.colors.Blue, bold = true },
}
ns = api.nvim_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 |
|
]],
}
api.nvim_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 |
|
]],
}
api.nvim_buf_set_extmark(0, ns, 0, 5, { virt_text = { { '' }, { '' } }, virt_text_pos = 'inline' })
api.nvim_buf_set_extmark(0, ns, 1, 14, { virt_text = { { '' }, { ': ', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_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 |
|
]],
}
api.nvim_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')]])
api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_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))]])
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(10), 'Special' } }, virt_text_pos = 'inline' })
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_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 '$'
api.nvim_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')
api.nvim_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')
api.nvim_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()
api.nvim_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
]])
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('X', 60), 'Special' } }, virt_text_pos = 'inline' })
api.nvim_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:~ }|*2
|
]],
}
feed('j')
screen:expect {
grid = [[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
aa^a |
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{10:X} |
bbbbbb |
{1:~ }|*2
|
]],
}
feed('j')
screen:expect {
grid = [[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
aaa |
{10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{10:X} |
bbbbbb |
{1:~ }|*2
|
]],
}
feed('j')
screen:expect {
grid = [[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
aaa |
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{10:X} |
bbbbb^b |
{1:~ }|*2
|
]],
}
feed('0<C-V>2l2k')
screen:expect {
grid = [[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{7:aa}^a |
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{10:X} |
{7:bbb}bbb |
{1:~ }|*2
{8:-- VISUAL BLOCK --} |
]],
}
feed([[<Esc>/aaa\n\%V<CR>]])
screen:expect {
grid = [[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{12:^aaa } |
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{10:X} |
bbbbbb |
{1:~ }|*2
{16:search hit BOTTOM, continuing at TOP} |
]],
}
feed('3ggic')
screen:expect {
grid = [[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{12:aaa } |
c{10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{10:XX} |
bbbbbb |
{1:~ }|*2
{8:-- INSERT --} |
]],
}
feed([[<Esc>/aaa\nc\%V<CR>]])
screen:expect {
grid = [[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{12:^aaa } |
{12:c}{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
{10:XX} |
bbbbbb |
{1:~ }|*2
{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>')
api.nvim_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')
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 9, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_buf_set_extmark(0, ns, 0, 9, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_buf_set_extmark(0, ns, 1, 9, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_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^ |
]],
}
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_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 --} |
]],
}
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' })
api.nvim_buf_set_extmark(0, ns, 0, 4, { end_col = 11, hl_group = 'Search' })
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_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))
api.nvim_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))
api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { ('>'):rep(32), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
feed('$')
screen:expect([[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
{1:~ }|
|
]])
command('set list listchars+=precedes:!')
screen:expect([[
{1:!}{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
{1:~ }|
|
]])
end)
it('draws correctly with no wrap and multibyte virtual text', function()
insert('12345678')
command('set nowrap')
api.nvim_buf_set_extmark(0, ns, 0, 2, {
hl_mode = 'replace',
virt_text = { { 'α口β̳γ̲=', 'Special' }, { '❤️', 'Special' } },
virt_text_pos = 'inline',
})
screen:expect([[
12{10:α口β̳γ̲=❤️}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
2{10:α口β̳γ̲=❤️}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:α口β̳γ̲=❤️}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:口β̳γ̲=❤️}34567^8 |
{1:~ }|
|
]])
feed('V')
screen:expect([[
{10:口β̳γ̲=❤️}{7:34567}^8 |
{1:~ }|
{8:-- VISUAL LINE --} |
]])
command('set list listchars+=precedes:!')
screen:expect([[
{1:!<}{10:β̳γ̲=❤️}{7:34567}^8 |
{1:~ }|
{8:-- VISUAL LINE --} |
]])
feed('zl')
screen:expect([[
{1:!}{10:β̳γ̲=❤️}{7:34567}^8 |
{1:~ }|
{8:-- VISUAL LINE --} |
]])
command('set nolist')
screen:expect([[
{1:<}{10:β̳γ̲=❤️}{7:34567}^8 |
{1:~ }|
{8:-- VISUAL LINE --} |
]])
feed('<Esc>')
screen:expect([[
{1:<}{10:β̳γ̲=❤️}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:β̳γ̲=❤️}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:γ̲=❤️}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:=❤️}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:❤️}34567^8 |
{1:~ }|
|
]])
command('set list')
screen:expect([[
{1:!<}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{1:!}34567^8 |
{1:~ }|
|
]])
command('set nolist')
screen:expect([[
{1:<}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
4567^8 |
{1:~ }|
|
]])
end)
it('tabs are the correct length with no wrap following virtual text', function()
command('set nowrap')
feed('itest<TAB>a<ESC>')
api.nvim_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')
api.nvim_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')
api.nvim_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')
api.nvim_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]])
api.nvim_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')
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
api.nvim_buf_set_extmark(0, ns, 5, 0, { virt_text = { { '!', 'Special' } }, virt_text_pos = 'inline' })
api.nvim_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: }|*2
{9:000 }│{5:9}{9:000 }|
{9:000 }│{9:000}{5:9}{9: }|
{9:aaabbb }│{14:!}{9:aaa}{5: }{9:bbb }|
{1:~ }│{1:~ }|*2
{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: }|*2
{9:000 }│{9:000 }|
{9:000 }│{9:00}{5:9}{9: }|
{9:aaabbb }│{9:aaa}{5: }{9:bb^b }|
{1:~ }│{1:~ }|*2
{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')
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' })
api.nvim_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>')
api.nvim_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]])
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' })
api.nvim_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:~ }|*2
|
]],
}
feed('j')
screen:expect {
grid = [[
{17:+-- 2 lines: aaaaa·······························································}|
{18:^+-- 2 lines: ccccc·······························································}|
{1:~ }|*2
|
]],
}
end)
it('does not crash at right edge of wide window #23848', function()
screen:try_resize(82, 5)
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { ('a'):rep(82) }, { 'b' } }, virt_text_pos = 'inline' })
screen:expect {
grid = [[
^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
b |
{1:~ }|*2
|
]],
}
command('set nowrap')
screen:expect {
grid = [[
^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1:~ }|*3
|
]],
}
feed('82i0<Esc>0')
screen:expect {
grid = [[
^0000000000000000000000000000000000000000000000000000000000000000000000000000000000|
{1:~ }|*3
|
]],
}
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))
]])
api.nvim_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')
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 1, 1, { virt_text = { { '-口-', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' })
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 1, 1, { virt_text = { { '-口-', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
api.nvim_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! $
]])
api.nvim_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:~ }|*2
: |
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:+}12312312312312312312312|
{1:+}3^a |
{1:~ }|*3
: |
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:+}3^a |
{1:~ }|*4
: |
]],
}
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:~ }|*2
: |
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:+}23123123123123123123123|
{1:+}^a |
{1:~ }|*3
: |
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:+}^a |
{1:~ }|*4
: |
]],
}
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:~ }|*2
: |
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:+}23123123123123123123123|
{1:+}^a |
{1:~ }|*3
: |
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:+}^a |
{1:~ }|*4
: |
]],
}
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:~ }|*2
{8:-- INSERT --} |
]],
}
feed('<Esc>')
screen:expect {
grid = [[
1 12312312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123^a |
{1:~ }|*2
|
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:+}31231231231231231231231|
{1:+}23123123123123123123^a |
{1:~ }|*3
|
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:+}23123123123123123123^a |
{1:~ }|*4
|
]],
}
feed('zbx')
screen:expect {
grid = [[
1 ^12312312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123 |
{1:~ }|*2
|
]],
}
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! $
]])
api.nvim_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:~ }|*2
|
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:<<<}2121212121212121212121212{1:<-}|
{1:----->}^a |
{1:~ }|*3
|
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:<<<-->}^a |
{1:~ }|*4
|
]],
}
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:~ }|*2
|
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:<<<}2121212121212121212121212 |
^ a |
{1:~ }|*3
|
]],
}
feed('<C-E>')
screen:expect {
grid = [[
{1:<<<} ^ a |
{1:~ }|*4
|
]],
}
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! $
]])
api.nvim_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:~ }|*2
|
]],
}
feed('05x$')
screen:expect {
grid = [[
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb|
{1:+}bbbbb |
{1:+}cccccccccccccccccccccccccccccccccccccccccccc^c |
{1:~ }|*2
|
]],
}
end)
it('before double-width char that wraps', function()
exec([[
call setline(1, repeat('a', 40) .. '口' .. '12345')
normal! $
]])
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(9) } }, virt_text_pos = 'inline' })
screen:expect([[
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
口1234^5 |
|
]])
feed('g0')
screen:expect([[
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
^口12345 |
|
]])
command('set showbreak=+++')
screen:expect([[
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
{1:+++}^口12345 |
|
]])
end)
it('cursor position is correct if end_row or end_col is specified', function()
screen:try_resize(50, 8)
api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48), ('c'):rep(48), ('d'):rep(48) })
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, virt_text_pos = 'inline', virt_text = { { 'I1', 'NonText' } } })
api.nvim_buf_set_extmark(0, ns, 3, 0, { end_col = 2, virt_text_pos = 'inline', virt_text = { { 'I2', 'NonText' } } })
feed('$')
screen:expect([[
{1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^a|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
cccccccccccccccccccccccccccccccccccccccccccccccc |
{1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
{1:~ }|*3
|
]])
feed('j')
screen:expect([[
{1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b |
cccccccccccccccccccccccccccccccccccccccccccccccc |
{1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
{1:~ }|*3
|
]])
feed('j')
screen:expect([[
{1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
ccccccccccccccccccccccccccccccccccccccccccccccc^c |
{1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
{1:~ }|*3
|
]])
feed('j')
screen:expect([[
{1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
cccccccccccccccccccccccccccccccccccccccccccccccc |
{1:I2}ddddddddddddddddddddddddddddddddddddddddddddddd^d|
{1:~ }|*3
|
]])
end)
it('is redrawn correctly after delete or redo #27370', function()
screen:try_resize(50, 12)
exec([[
call setline(1, ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff'])
call setline(3, repeat('c', winwidth(0) - 1))
]])
api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { '!!!' } }, virt_text_pos = 'inline' })
feed('j')
local before_delete = [[
aaa |
!!!^bbb |
ccccccccccccccccccccccccccccccccccccccccccccccccc |
ddd |
eee |
fff |
{1:~ }|*5
|
]]
screen:expect(before_delete)
feed('dd')
local after_delete = [[
aaa |
!!!^ccccccccccccccccccccccccccccccccccccccccccccccc|
cc |
ddd |
eee |
fff |
{1:~ }|*5
|
]]
screen:expect(after_delete)
command('silent undo')
screen:expect(before_delete)
command('silent redo')
screen:expect(after_delete)
command('silent undo')
screen:expect(before_delete)
command('set report=100')
feed('yypk2P')
before_delete = [[
aaa |
^bbb |
bbb |
!!!bbb |
bbb |
ccccccccccccccccccccccccccccccccccccccccccccccccc |
ddd |
eee |
fff |
{1:~ }|*2
|
]]
screen:expect(before_delete)
feed('4dd')
screen:expect(after_delete)
command('silent undo')
screen:expect(before_delete)
command('silent redo')
screen:expect(after_delete)
end)
it('cursor position is correct with invalidated inline virt text', function()
screen:try_resize(50, 8)
api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48) })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text_pos = 'inline', virt_text = { { 'INLINE', 'NonText' } }, invalidate = true })
screen:expect([[
{1:INLINE}^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaa |
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
{1:~ }|*4
|
]])
feed('dd$')
screen:expect([[
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b |
{1:~ }|*6
|
]])
end)
it('line size is correct with inline virt text at EOL and showbreak', function()
screen:try_resize(50, 8)
insert(('0123456789'):rep(5) .. '\nfoo\nbar')
api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { ('x'):rep(145), 'ErrorMsg' } }, virt_text_pos = 'inline' })
command([[set cursorline scrolloff=0 showbreak=>\ smoothscroll]])
screen:expect([[
01234567890123456789012345678901234567890123456789|
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
{1:> }{4:x} |
foo |
{22:ba^r }|
|
]])
eq(5, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all)
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
{1:> }{4:x} |
foo |
{22:ba^r }|
{1:~ }|
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
{1:> }{4:x} |
foo |
{22:ba^r }|
{1:~ }|*2
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|
{1:> }{4:x} |
foo |
{22:ba^r }|
{1:~ }|*3
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:x} |
foo |
{22:ba^r }|
{1:~ }|*4
|
]])
feed('<C-E>')
screen:expect([[
foo |
{22:ba^r }|
{1:~ }|*5
|
]])
feed('gg$xG$')
screen:expect([[
0123456789012345678901234567890123456789012345678{4:x}|
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
foo |
{22:ba^r }|
{1:~ }|
|
]])
eq(4, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all)
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
foo |
{22:ba^r }|
{1:~ }|*2
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
foo |
{22:ba^r }|
{1:~ }|*3
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|
foo |
{22:ba^r }|
{1:~ }|*4
|
]])
feed('<C-E>')
screen:expect([[
foo |
{22:ba^r }|
{1:~ }|*5
|
]])
feed('zb')
command('set list listchars=eol:$')
screen:expect([[
0123456789012345678901234567890123456789012345678{4:x}|
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
{1:> $} |
foo{1:$} |
{22:ba^r}{23:$}{22: }|
|
]])
eq(5, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all)
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
{1:> $} |
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
{1:> $} |
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|*2
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|
{1:> $} |
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|*3
|
]])
feed('<C-E>')
screen:expect([[
{1:> $} |
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|*4
|
]])
feed('<C-E>')
screen:expect([[
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|*5
|
]])
feed('gg$xG$')
screen:expect([[
012345678901234567890123456789012345678901234567{4:xx}|
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}|
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|
|
]])
eq(4, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all)
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}|
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|*2
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}|
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|*3
|
]])
feed('<C-E>')
screen:expect([[
{1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}|
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|*4
|
]])
feed('<C-E>')
screen:expect([[
foo{1:$} |
{22:ba^r}{23:$}{22: }|
{1:~ }|*5
|
]])
end)
it("virtcol('$') is correct with inline virt text at EOL", function()
insert(('1234567890\n'):rep(6))
for _, v in ipairs({ { 2, 'a' }, { 3, 'ab' }, { 4, 'abc' }, { 5, 'abcd' }, { 6, 'αβγ口' } }) do
local ln, tx = unpack(v)
local co = fn.col({ ln, '$' })
eq(11, fn.virtcol({ ln, '$' }))
api.nvim_buf_set_extmark(0, ns, ln - 1, co - 1, { virt_text = { { tx } }, virt_text_pos = 'inline' })
eq(11 + fn.strwidth(tx), fn.virtcol({ ln, '$' }))
end
end)
end)
describe('decorations: virtual lines', function()
local screen ---@type test.functional.ui.screen
local ns ---@type integer
before_each(function()
clear()
screen = Screen.new(50, 12)
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow },
}
ns = api.nvim_create_namespace 'test'
end)
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;
if (kh_is_map && val_size) {
char *new_vals = krealloc( h->vals_buf, new_n_buckets * val_size);
h->vals_buf = new_vals;
}
}]]
it('works with one line', function()
insert(example_text2)
feed '2gg'
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
^khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
{1:~ }|
|
]],
}
api.nvim_buf_set_extmark(0, ns, 1, 33, {
virt_lines = { { { '>> ', 'NonText' }, { 'krealloc', 'Identifier' }, { ': change the size of an allocation' } } },
virt_lines_above = true,
})
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
{1:>> }{25:krealloc}: change the size of an allocation |
^khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
|
]],
}
feed '/krealloc<cr>'
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
{1:>> }{25:krealloc}: change the size of an allocation |
khkey_t *new_keys = (khkey_t *){10:^krealloc}((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
/krealloc |
]],
}
-- virtual line remains anchored to the extmark
feed 'i<cr>'
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *) |
{1:>> }{25:krealloc}: change the size of an allocation |
{10:^krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
hkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
{5:-- INSERT --} |
]],
}
feed '<esc>3+'
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *) |
{1:>> }{25:krealloc}: change the size of an allocation |
{10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
hkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
^char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
|
]],
}
api.nvim_buf_set_extmark(0, ns, 5, 0, {
virt_lines = { { { '^^ REVIEW:', 'Todo' }, { ' new_vals variable seems unnecessary?', 'Comment' } } },
})
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *) |
{1:>> }{25:krealloc}: change the size of an allocation |
{10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
hkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
^char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
buckets * val_size); |
{100:^^ REVIEW:}{18: new_vals variable seems unnecessary?} |
h->vals_buf = new_vals; |
|
]],
}
api.nvim_buf_clear_namespace(0, ns, 0, -1)
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *) |
{10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
hkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
^char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
|
]],
}
end)
it('works with text at the beginning of the buffer', function()
insert(example_text2)
feed 'gg'
screen:expect {
grid = [[
^if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
{1:~ }|
|
]],
}
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { 'refactor(khash): ', 'Special' }, { 'take size of values as parameter' } },
{ { 'Author: Dev Devsson, ' }, { 'Tue Aug 31 10:13:37 2021', 'Comment' } },
},
virt_lines_above = true,
right_gravity = false,
})
-- placing virt_text on topline does not automatically cause a scroll
screen:expect {
grid = [[
^if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
{1:~ }|
|
]],
unchanged = true,
}
feed '<c-b>'
screen:expect {
grid = [[
{16:refactor(khash): }take size of values as parameter |
Author: Dev Devsson, {18:Tue Aug 31 10:13:37 2021} |
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
^} |
|
]],
}
end)
it('works with text at the end of the buffer', function()
insert(example_text2)
feed 'G'
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
^} |
{1:~ }|
|
]],
}
local id = api.nvim_buf_set_extmark(0, ns, 7, 0, {
virt_lines = { { { 'Grugg' } } },
right_gravity = false,
})
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
^} |
Grugg |
|
]],
}
screen:try_resize(50, 11)
feed('gg')
screen:expect {
grid = [[
^if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
|
]],
}
feed('G<C-E>')
screen:expect {
grid = [[
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
^} |
Grugg |
|
]],
}
feed('gg')
screen:expect {
grid = [[
^if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
|
]],
}
screen:try_resize(50, 12)
feed('G')
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
^} |
Grugg |
|
]],
}
api.nvim_buf_del_extmark(0, ns, id)
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
^} |
{1:~ }|
|
]],
}
end)
it('works beyond end of the buffer with virt_lines_above', function()
insert(example_text2)
feed 'G'
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
^} |
{1:~ }|
|
]],
}
local id = api.nvim_buf_set_extmark(0, ns, 8, 0, {
virt_lines = { { { 'Grugg' } } },
virt_lines_above = true,
})
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
^} |
Grugg |
|
]],
}
feed('dd')
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
^} |
Grugg |
{1:~ }|
|
]],
}
feed('dk')
screen:expect {
grid = [[
if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
^char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
Grugg |
{1:~ }|*3
|
]],
}
feed('dgg')
screen:expect {
grid = [[
^ |
Grugg |
{1:~ }|*9
--No lines in buffer-- |
]],
}
api.nvim_buf_del_extmark(0, ns, id)
screen:expect {
grid = [[
^ |
{1:~ }|*10
--No lines in buffer-- |
]],
}
end)
it('does not cause syntax ml_get error at the end of a buffer #17816', function()
command([[syntax region foo keepend start='^foo' end='^$']])
command('syntax sync minlines=100')
insert('foo')
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'bar', 'Comment' } } } })
screen:expect([[
fo^o |
{18:bar} |
{1:~ }|*9
|
]])
end)
it('works with a block scrolling up', function()
screen:try_resize(30, 7)
insert('aa\nbb\ncc\ndd\nee\nff\ngg\nhh')
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 6, 0, {
virt_lines = {
{ { 'they see me' } },
{ { 'scrolling', 'Special' } },
{ { 'they' } },
{ { "hatin'", 'Special' } },
},
})
screen:expect {
grid = [[
^aa |
bb |
cc |
dd |
ee |
ff |
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
^bb |
cc |
dd |
ee |
ff |
gg |
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
^cc |
dd |
ee |
ff |
gg |
they see me |
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
^dd |
ee |
ff |
gg |
they see me |
{16:scrolling} |
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
^ee |
ff |
gg |
they see me |
{16:scrolling} |
they |
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
^ff |
gg |
they see me |
{16:scrolling} |
they |
{16:hatin'} |
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
^gg |
they see me |
{16:scrolling} |
they |
{16:hatin'} |
hh |
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
they see me |
{16:scrolling} |
they |
{16:hatin'} |
^hh |
{1:~ }|
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
{16:scrolling} |
they |
{16:hatin'} |
^hh |
{1:~ }|*2
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
they |
{16:hatin'} |
^hh |
{1:~ }|*3
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
{16:hatin'} |
^hh |
{1:~ }|*4
|
]],
}
feed '<c-e>'
screen:expect {
grid = [[
^hh |
{1:~ }|*5
|
]],
}
end)
it('works with sign and numbercolumns', function()
insert(example_text2)
feed 'gg'
command 'set number signcolumn=yes'
screen:expect([[
{7: }{8: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
{7: }{8: }d |
{7: }{8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
{7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
{7: }{8: }t)); |
{7: }{8: 3 } h->keys = new_keys; |
{7: }{8: 4 } if (kh_is_map && val_size) { |
{7: }{8: 5 } char *new_vals = krealloc( h->vals_buf, |
{7: }{8: }new_n_buckets * val_size); |
{7: }{8: 6 } h->vals_buf = new_vals; |
{7: }{8: 7 } } |
|
]])
local markid = api.nvim_buf_set_extmark(0, ns, 2, 0, {
virt_lines = {
{ { 'Some special', 'Special' } },
{ { 'remark about codes', 'Comment' } },
},
})
screen:expect([[
{7: }{8: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
{7: }{8: }d |
{7: }{8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
{7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
{7: }{8: }t)); |
{7: }{8: 3 } h->keys = new_keys; |
{7: }{8: }{16:Some special} |
{7: }{8: }{18:remark about codes} |
{7: }{8: 4 } if (kh_is_map && val_size) { |
{7: }{8: 5 } char *new_vals = krealloc( h->vals_buf, |
{7: }{8: }new_n_buckets * val_size); |
|
]])
api.nvim_buf_set_extmark(0, ns, 2, 0, {
virt_lines = {
{ { 'Some special', 'Special' } },
{ { 'remark about codes', 'Comment' } },
},
virt_lines_leftcol = true,
id = markid,
})
screen:expect([[
{7: }{8: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
{7: }{8: }d |
{7: }{8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
{7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
{7: }{8: }t)); |
{7: }{8: 3 } h->keys = new_keys; |
{16:Some special} |
{18:remark about codes} |
{7: }{8: 4 } if (kh_is_map && val_size) { |
{7: }{8: 5 } char *new_vals = krealloc( h->vals_buf, |
{7: }{8: }new_n_buckets * val_size); |
|
]])
command('set nonumber relativenumber')
screen:expect([[
{7: }{8: 0 }^if (h->n_buckets < new_n_buckets) { // expan|
{7: }{8: }d |
{7: }{8: 1 } khkey_t *new_keys = (khkey_t *)krealloc((v|
{7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
{7: }{8: }t)); |
{7: }{8: 2 } h->keys = new_keys; |
{16:Some special} |
{18:remark about codes} |
{7: }{8: 3 } if (kh_is_map && val_size) { |
{7: }{8: 4 } char *new_vals = krealloc( h->vals_buf, |
{7: }{8: }new_n_buckets * val_size); |
|
]])
-- 'relativenumber' is redrawn with virt_lines_leftcol #34649
feed('j')
screen:expect([[
{7: }{8: 1 }if (h->n_buckets < new_n_buckets) { // expan|
{7: }{8: }d |
{7: }{8: 0 }^ khkey_t *new_keys = (khkey_t *)krealloc((v|
{7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
{7: }{8: }t)); |
{7: }{8: 1 } h->keys = new_keys; |
{16:Some special} |
{18:remark about codes} |
{7: }{8: 2 } if (kh_is_map && val_size) { |
{7: }{8: 3 } char *new_vals = krealloc( h->vals_buf, |
{7: }{8: }new_n_buckets * val_size); |
|
]])
end)
it('works with hard TABs', function()
insert(example_text2)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, 0, {
virt_lines = { { { '>>', 'NonText' }, { '\tvery\ttabby', 'Identifier' }, { 'text\twith\ttabs' } } },
})
screen:expect {
grid = [[
^if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
{1:>>}{25: very tabby}text with tabs |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
|
]],
}
command 'set tabstop=4'
screen:expect {
grid = [[
^if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *)krealloc((void *)|
h->keys, new_n_buckets * sizeof(khkey_t)); |
{1:>>}{25: very tabby}text with tabs |
h->keys = new_keys; |
if (kh_is_map && val_size) { |
char *new_vals = krealloc( h->vals_buf, new_n_|
buckets * val_size); |
h->vals_buf = new_vals; |
} |
} |
|
]],
}
command 'set number'
screen:expect {
grid = [[
{8: 1 }^if (h->n_buckets < new_n_buckets) { // expand |
{8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((voi|
{8: }d *)h->keys, new_n_buckets * sizeof(khkey_t));|
{8: }{1:>>}{25: very tabby}text with tabs |
{8: 3 } h->keys = new_keys; |
{8: 4 } if (kh_is_map && val_size) { |
{8: 5 } char *new_vals = krealloc( h->vals_buf, ne|
{8: }w_n_buckets * val_size); |
{8: 6 } h->vals_buf = new_vals; |
{8: 7 } } |
{8: 8 }} |
|
]],
}
command 'set tabstop&'
screen:expect {
grid = [[
{8: 1 }^if (h->n_buckets < new_n_buckets) { // expand |
{8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((voi|
{8: }d *)h->keys, new_n_buckets * sizeof(khkey_t));|
{8: }{1:>>}{25: very tabby}text with tabs |
{8: 3 } h->keys = new_keys; |
{8: 4 } if (kh_is_map && val_size) { |
{8: 5 } char *new_vals = krealloc( h->vals_buf, ne|
{8: }w_n_buckets * val_size); |
{8: 6 } h->vals_buf = new_vals; |
{8: 7 } } |
{8: 8 }} |
|
]],
}
end)
it('scrolls horizontally with virt_lines_overflow=scroll #31000', function()
command('set nowrap signcolumn=yes')
insert('abcdefghijklmnopqrstuvwxyz')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { '12α口β̳γ̲=', 'Special' }, { '❤️345678', 'Special' } },
{ { '123\t45\t678', 'NonText' } },
},
virt_lines_overflow = 'scroll',
})
screen:expect([[
{7: }abcdefghijklmnopqrstuvwxy^z |
{7: }{16:12α口β̳γ̲=❤️345678} |
{7: }{1:123 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }bcdefghijklmnopqrstuvwxy^z |
{7: }{16:2α口β̳γ̲=❤️345678} |
{7: }{1:23 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }cdefghijklmnopqrstuvwxy^z |
{7: }{16:α口β̳γ̲=❤️345678} |
{7: }{1:3 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }defghijklmnopqrstuvwxy^z |
{7: }{16:口β̳γ̲=❤️345678} |
{7: }{1: 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }efghijklmnopqrstuvwxy^z |
{7: }{16: β̳γ̲=❤️345678} |
{7: }{1: 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }fghijklmnopqrstuvwxy^z |
{7: }{16:β̳γ̲=❤️345678} |
{7: }{1: 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }ghijklmnopqrstuvwxy^z |
{7: }{16:γ̲=❤️345678} |
{7: }{1: 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }hijklmnopqrstuvwxy^z |
{7: }{16:=❤️345678} |
{7: }{1: 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }ijklmnopqrstuvwxy^z |
{7: }{16:❤️345678} |
{7: }{1:45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }jklmnopqrstuvwxy^z |
{7: }{16: 345678} |
{7: }{1:5 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }klmnopqrstuvwxy^z |
{7: }{16:345678} |
{7: }{1: 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }lmnopqrstuvwxy^z |
{7: }{16:45678} |
{7: }{1: 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }mnopqrstuvwxy^z |
{7: }{16:5678} |
{7: }{1: 678} |
{1:~ }|*8
|
]])
api.nvim_buf_set_extmark(0, ns, 0, 1, {
virt_lines = { { { '123\t45\t67', 'NonText' } } },
virt_lines_leftcol = true,
virt_lines_overflow = 'trunc',
})
api.nvim_buf_set_extmark(0, ns, 0, 2, {
virt_lines = { { { '123\t45\t6', 'NonText' } } },
virt_lines_leftcol = false,
virt_lines_overflow = 'trunc',
})
screen:expect([[
{7: }mnopqrstuvwxy^z |
{7: }{16:5678} |
{7: }{1: 678} |
{1:123 45 67} |
{7: }{1:123 45 6} |
{1:~ }|*6
|
]])
end)
it('virt_lines_overflow=wrap', function()
command('set wrap signcolumn=yes')
insert('line1\nline2\nline3\n')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{
{
string.rep(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean non felis dapibus, semper sapien vitae, fringilla orci.',
5
),
'Special',
},
},
},
virt_lines_overflow = 'wrap',
})
screen:expect([[
{7: }{16:rem ipsum dolor sit amet, consectetur adipiscing}|
{7: }{16: elit. Aenean non felis dapibus, semper sapien v}|
{7: }{16:itae, fringilla orci.Lorem ipsum dolor sit amet,}|
{7: }{16: consectetur adipiscing elit. Aenean non felis d}|
{7: }{16:apibus, semper sapien vitae, fringilla orci.Lore}|
{7: }{16:m ipsum dolor sit amet, consectetur adipiscing e}|
{7: }{16:lit. Aenean non felis dapibus, semper sapien vit}|
{7: }{16:ae, fringilla orci.} |
{7: }line2 |
{7: }line3 |
{7: }^ |
|
]])
feed('<C-e>')
screen:expect([[
{7: }{16: elit. Aenean non felis dapibus, semper sapien v}|
{7: }{16:itae, fringilla orci.Lorem ipsum dolor sit amet,}|
{7: }{16: consectetur adipiscing elit. Aenean non felis d}|
{7: }{16:apibus, semper sapien vitae, fringilla orci.Lore}|
{7: }{16:m ipsum dolor sit amet, consectetur adipiscing e}|
{7: }{16:lit. Aenean non felis dapibus, semper sapien vit}|
{7: }{16:ae, fringilla orci.} |
{7: }line2 |
{7: }line3 |
{7: }^ |
{1:~ }|
|
]])
feed('<C-e>')
screen:expect([[
{7: }{16:itae, fringilla orci.Lorem ipsum dolor sit amet,}|
{7: }{16: consectetur adipiscing elit. Aenean non felis d}|
{7: }{16:apibus, semper sapien vitae, fringilla orci.Lore}|
{7: }{16:m ipsum dolor sit amet, consectetur adipiscing e}|
{7: }{16:lit. Aenean non felis dapibus, semper sapien vit}|
{7: }{16:ae, fringilla orci.} |
{7: }line2 |
{7: }line3 |
{7: }^ |
{1:~ }|*2
|
]])
end)
it('virt_lines_overflow=wrap with 2 cell character', function()
command('set wrap signcolumn=yes')
insert('line1\nline2\nline3\n')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { string.rep('12345678古', 5), 'Special' } },
},
virt_lines_overflow = 'wrap',
})
screen:expect([[
{7: }line1 |
{7: }{16:12345678古12345678古12345678古12345678古12345678}|
{7: }{16:古} |
{7: }line2 |
{7: }line3 |
{7: }^ |
{1:~ }|*5
|
]])
feed('<C-e>')
screen:expect([[
{7: }{16:12345678古12345678古12345678古12345678古12345678}|
{7: }{16:古} |
{7: }line2 |
{7: }line3 |
{7: }^ |
{1:~ }|*6
|
]])
feed('<C-e>')
screen:expect([[
{7: }{16:古} |
{7: }line2 |
{7: }line3 |
{7: }^ |
{1:~ }|*7
|
]])
end)
it('virt_lines_overflow=wrap with tabs', function()
command('set wrap signcolumn=yes')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { string.rep('1234\t\t\t5\t6\t78古', 10), 'Special' } },
},
virt_lines_overflow = 'wrap',
})
screen:expect([[
{7: }^ |
{7: }{16:1234 5 6 78古1234}|
{7: }{16: 5 6 78古1234}|*8
{7: }{16: 5 6 78古} |
|
]])
end)
it('virt_lines_overflow=wrap with 2 cell character at the boundary', function()
insert('x')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = { { { string.rep('a', 49) .. string.rep('古', 4), 'Special' } } },
virt_lines_overflow = 'wrap',
})
screen:expect([[
^x |
{16:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa }|
{16:古古古古} |
{1:~ }|*8
|
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
screen:try_resize(13, 10)
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { 'AB', 'Special' } },
{ { string.rep('古', 13), 'Special' } },
},
virt_lines_overflow = 'wrap',
})
screen:expect([[
^x |
{16:AB} |
{16:古古古古古古 }|*2
{16:古} |
{1:~ }|*4
|
]])
end)
it('virt_lines_overflow=wrap with nowrap', function()
command('set nowrap signcolumn=yes')
insert(string.rep('abcdefghij', 6) .. 'line1\nline2\nline3\n')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { string.rep('12345678古', 5), 'Special' } },
},
virt_lines_overflow = 'wrap',
})
feed('ggzlzl')
screen:expect([[
{7: }^cdefghijabcdefghijabcdefghijabcdefghijabcdefghij|
{7: }{16:12345678古12345678古12345678古12345678古12345678}|
{7: }{16:古} |
{7: }ne2 |
{7: }ne3 |
{7: } |
{1:~ }|*5
|
]])
end)
it('virt_lines_overflow=auto with wrap', function()
command('set wrap signcolumn=yes')
insert('line1\nline2\nline3\n')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { string.rep('Thequickbrownfoxjumpsoverthelazydog. The quick brown fox jumps over the lazy dog', 20), 'Special' } },
},
virt_lines_overflow = 'auto',
})
screen:expect([[
{7: }{16:rown fox jumps over the lazy dogThequickbrownfox}|
{7: }{16:jumpsoverthelazydog. The quick brown fox jumps o}|
{7: }{16:ver the lazy dogThequickbrownfoxjumpsoverthelazy}|
{7: }{16:dog. The quick brown fox jumps over the lazy dog}|
{7: }{16:Thequickbrownfoxjumpsoverthelazydog. The quick b}|
{7: }{16:rown fox jumps over the lazy dogThequickbrownfox}|
{7: }{16:jumpsoverthelazydog. The quick brown fox jumps o}|
{7: }{16:ver the lazy dog} |
{7: }line2 |
{7: }line3 |
{7: }^ |
|
]])
end)
it('virt_lines_overflow=auto and nowrap scrolls horizontally', function()
command('set nowrap signcolumn=yes')
insert('abcdefghijklmnopqrstuvwxyz')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { '12α口β̳γ̲=', 'Special' }, { '❤️345678', 'Special' } },
{ { '123\t45\t678', 'NonText' } },
},
virt_lines_overflow = 'auto',
})
screen:expect([[
{7: }abcdefghijklmnopqrstuvwxy^z |
{7: }{16:12α口β̳γ̲=❤️345678} |
{7: }{1:123 45 678} |
{1:~ }|*8
|
]])
feed('zl')
screen:expect([[
{7: }bcdefghijklmnopqrstuvwxy^z |
{7: }{16:2α口β̳γ̲=❤️345678} |
{7: }{1:23 45 678} |
{1:~ }|*8
|
]])
end)
it('virt_lines_overflow=wrap with virt_lines_above + virt_lines_leftcol', function()
command('set wrap signcolumn=yes')
insert('line1\nline2\nline3\n')
feed('2gg')
api.nvim_buf_set_extmark(0, ns, 1, 0, {
virt_lines = {
{ { string.rep('Lorem ipsum dolor sit amet, consectetur. ', 6), 'Special' } },
},
virt_lines_overflow = 'wrap',
virt_lines_above = true,
virt_lines_leftcol = true,
})
screen:expect([[
{7: }line1 |
{16:Lorem ipsum dolor sit amet, consectetur. Lorem ips}|
{16:um dolor sit amet, consectetur. Lorem ipsum dolor }|
{16:sit amet, consectetur. Lorem ipsum dolor sit amet,}|
{16: consectetur. Lorem ipsum dolor sit amet, consecte}|
{16:tur. Lorem ipsum dolor sit amet, consectetur. } |
{7: }^line2 |
{7: }line3 |
{7: } |
{1:~ }|*2
|
]])
end)
it('virt_lines_overflow=wrap with wrapped rows for statuscolumn', function()
command('set wrap statuscolumn=[%{v:lnum}]')
insert('line1\nline2\nline3\n')
feed('2gg')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = {
{ { 'BELOW ' .. string.rep('Lorem ipsum dolor sit amet, consectetur. ', 4), 'Special' } },
},
virt_lines_overflow = 'wrap',
})
api.nvim_buf_set_extmark(0, ns, 1, 0, {
virt_lines = {
{ { 'ABOVE ' .. string.rep('Lorem ipsum dolor sit amet, consectetur. ', 4), 'Special' } },
},
virt_lines_overflow = 'wrap',
virt_lines_above = true,
})
screen:expect([[
{8:[1]}line1 |
{8:[1]}{16:BELOW Lorem ipsum dolor sit amet, consectetur. }|
{8:[1]}{16:Lorem ipsum dolor sit amet, consectetur. Lorem }|
{8:[1]}{16:ipsum dolor sit amet, consectetur. Lorem ipsum }|
{8:[1]}{16:dolor sit amet, consectetur. } |
{8:[2]}{16:ABOVE Lorem ipsum dolor sit amet, consectetur. }|
{8:[2]}{16:Lorem ipsum dolor sit amet, consectetur. Lorem }|
{8:[2]}{16:ipsum dolor sit amet, consectetur. Lorem ipsum }|
{8:[2]}{16:dolor sit amet, consectetur. } |
{8:[2]}^line2 |
{8:[3]}line3 |
|
]])
end)
it('mixing virt_lines_overflow=wrap and virt_lines_overflow=scroll', function()
command('set nowrap signcolumn=yes')
insert('line1\nline2\nline3\n')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = { { { 'BELOW ' .. string.rep('a', 60), 'Special' } } },
virt_lines_overflow = 'wrap',
})
api.nvim_buf_set_extmark(0, ns, 1, 0, {
virt_lines = { { { 'ABOVE ' .. string.rep('b', 60), 'Special' } } },
virt_lines_overflow = 'scroll',
virt_lines_above = true,
})
api.nvim_buf_set_extmark(0, ns, 1, 0, {
virt_lines = { { { 'BELOW ' .. string.rep('c', 60), 'Special' } } },
virt_lines_overflow = 'scroll',
})
api.nvim_buf_set_extmark(0, ns, 2, 0, {
virt_lines = { { { 'ABOVE ' .. string.rep('d', 60), 'Special' } } },
virt_lines_overflow = 'wrap',
virt_lines_above = true,
})
feed('2ggzlzl')
screen:expect([[
{7: }ne1 |
{7: }{16:BELOW aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{7: }{16:aaaaaaaaaaaaaaaaaa} |
{7: }{16:OVE bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb}|
{7: }^ne2 |
{7: }{16:LOW cccccccccccccccccccccccccccccccccccccccccccc}|
{7: }{16:ABOVE dddddddddddddddddddddddddddddddddddddddddd}|
{7: }{16:dddddddddddddddddd} |
{7: }ne3 |
{7: } |
{1:~ }|
|
]])
end)
it('highlight till eol with virt_lines_overflow=trunc', function()
insert('line1')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = { { { 'VIRT LINE1', 'String' }, { '', 'Visual' } }, { { 'VIRT LINE2', 'String' } } },
})
screen:expect([[
line^1 |
{26:VIRT LINE1}{17: }|
{26:VIRT LINE2} |
{1:~ }|*8
|
]])
end)
it('highlight till eol with virt_lines_overflow=wrap', function()
insert('line1')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = { { { 'VIRT LINE', 'String' }, { string.rep('-', 50), 'Visual' }, { '', 'Visual' } } },
virt_lines_overflow = 'wrap',
})
screen:expect([[
line^1 |
{26:VIRT LINE}{17:-----------------------------------------}|
{17:--------- }|
{1:~ }|*8
|
]])
end)
it('highlight till eol with virt_lines_overflow=scroll', function()
command('set nowrap')
insert('abcdefghijklmnopqrstuvwxyz')
api.nvim_buf_set_extmark(0, ns, 0, 0, {
virt_lines = { { { 'VIRT LINE', 'String' }, { '', 'Visual' } } },
virt_lines_overflow = 'scroll',
})
screen:expect([[
abcdefghijklmnopqrstuvwxy^z |
{26:VIRT LINE}{17: }|
{1:~ }|*9
|
]])
feed('zl')
screen:expect([[
bcdefghijklmnopqrstuvwxy^z |
{26:IRT LINE}{17: }|
{1:~ }|*9
|
]])
feed('zl')
screen:expect([[
cdefghijklmnopqrstuvwxy^z |
{26:RT LINE}{17: }|
{1:~ }|*9
|
]])
feed('6zl')
screen:expect([[
ijklmnopqrstuvwxy^z |
{26:E}{17: }|
{1:~ }|*9
|
]])
feed('zl')
screen:expect([[
jklmnopqrstuvwxy^z |
{17: }|
{1:~ }|*9
|
]])
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]])
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, virt_lines = { { { 'VIRT LINE 1', 'NonText' } } } })
api.nvim_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')
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT LINE 1', 'NonText' } } }, virt_lines_leftcol = true })
api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'VIRT LINE 2', 'NonText' } } } })
screen:expect {
grid = [[
aaa{8: 1 }|
{1:1 ENIL TRIV}|
bbb{8: 2 }|
ccc{8: 3 }|
^ddd{8: 4 }|
{1:2 ENIL TRIV}{8: }|
{1: ~}|
|
]],
}
end)
it('works when using dd or yyp #23915 #23916', function()
insert([[
line1
line2
line3
line4
line5]])
api.nvim_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:~ }|*3
|
]],
}
feed('gg')
feed('yyp')
screen:expect {
grid = [[
line1 |
foo |
bar |
baz |
^line1 |
line2 |
line3 |
line4 |
line5 |
{1:~ }|*2
|
]],
}
feed('dd')
screen:expect {
grid = [[
line1 |
foo |
bar |
baz |
^line2 |
line3 |
line4 |
line5 |
{1:~ }|*3
|
]],
}
feed('kdd')
screen:expect([[
^line2 |
foo |
bar |
baz |
line3 |
line4 |
line5 |
{1:~ }|*4
|
]])
end)
it('does not break cursor position with concealcursor #27887', function()
command('vsplit')
insert('\n')
api.nvim_set_option_value('conceallevel', 2, {})
api.nvim_set_option_value('concealcursor', 'niv', {})
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT1' } }, { { 'VIRT2' } } } })
screen:expect([[
│ |
VIRT1 │VIRT1 |
VIRT2 │VIRT2 |
^ │ |
{1:~ }│{1:~ }|*6
{3:[No Name] [+] }{2:[No Name] [+] }|
|
]])
end)
it('works with full page scrolling #28290', function()
screen:try_resize(20, 8)
command('call setline(1, range(20))')
api.nvim_buf_set_extmark(0, ns, 10, 0, { virt_lines = { { { 'VIRT1' } }, { { 'VIRT2' } } } })
screen:expect([[
^0 |
1 |
2 |
3 |
4 |
5 |
6 |
|
]])
feed('<C-F>')
screen:expect([[
^5 |
6 |
7 |
8 |
9 |
10 |
VIRT1 |
|
]])
feed('<C-F>')
screen:expect([[
^10 |
VIRT1 |
VIRT2 |
11 |
12 |
13 |
14 |
|
]])
feed('<C-F>')
screen:expect([[
^13 |
14 |
15 |
16 |
17 |
18 |
19 |
|
]])
feed('<C-B>')
screen:expect([[
10 |
VIRT1 |
VIRT2 |
11 |
12 |
13 |
^14 |
|
]])
feed('<C-B>')
screen:expect([[
5 |
6 |
7 |
8 |
9 |
^10 |
VIRT1 |
|
]])
feed('<C-B>')
screen:expect([[
0 |
1 |
2 |
3 |
4 |
5 |
^6 |
|
]])
end)
it('not drawn when invalid', function()
api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT1' } } }, invalidate = true })
screen:expect({
grid = [[
^foo |
VIRT1 |
bar |
{1:~ }|*8
|
]],
})
feed('dd')
screen:expect({
grid = [[
^bar |
{1:~ }|*10
|
]],
})
end)
it("not revealed before skipcol scrolling up with 'smoothscroll'", function()
api.nvim_set_option_value('smoothscroll', true, {})
api.nvim_buf_set_lines(0, 0, -1, false, { ('x'):rep(screen._width * 2) })
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines_above = true, virt_lines = { { { 'VIRT1' } } } })
feed('<C-E>')
screen:expect([[
{1:<<<}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x|
{1:~ }|*10
|
]])
feed('<C-Y>')
screen:expect([[
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x|
{1:~ }|*9
|
]])
feed('<C-Y>')
screen:expect([[
VIRT1 |
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x|
{1:~ }|*8
|
]])
end)
end)
describe('decorations: signs', function()
local screen ---@type test.functional.ui.screen
local ns ---@type integer
before_each(function()
clear()
screen = Screen.new(50, 10)
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow },
}
ns = api.nvim_create_namespace 'test'
api.nvim_set_option_value('signcolumn', 'auto:9', {})
end)
local example_test3 = [[
l1
l2
l3
l4
l5
]]
it('can add a single sign (no end row)', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S' })
screen:expect([[
{7: }^l1 |
{7:S }l2 |
{7: }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('can add a single sign (with end row)', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S', end_row = 1 })
screen:expect([[
{7: }^l1 |
{7:S }l2 |
{7: }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('can add a single sign and text highlight', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = 'S', hl_group = 'Todo', end_col = 1 })
screen:expect([[
{7: }^l1 |
{7:S }{100:l}2 |
{7: }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
it('can add multiple signs (single extmark)', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S', end_row = 2 })
screen:expect([[
{7: }^l1 |
{7:S }l2 |
{7:S }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('can add multiple signs (multiple extmarks)', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S1' })
api.nvim_buf_set_extmark(0, ns, 3, -1, { sign_text = 'S2', end_row = 4 })
screen:expect([[
{7: }^l1 |
{7:S1}l2 |
{7: }l3 |
{7:S2}l4 |
{7:S2}l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('can add multiple signs (multiple extmarks) 2', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 3, -1, { sign_text = 'S1' })
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2', end_row = 3 })
screen:expect([[
{7: }^l1 |
{7:S2 }l2 |
{7:S2 }l3 |
{7:S2S1}l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('can add multiple signs (multiple extmarks) 3', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S1', end_row = 2 })
api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S2', end_row = 3 })
screen:expect([[
{7: }^l1 |
{7:S1 }l2 |
{7:S2S1}l3 |
{7:S2 }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('can add multiple signs (multiple extmarks) 4', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', end_row = 0 })
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2', end_row = 1 })
screen:expect([[
{7:S1}^l1 |
{7:S2}l2 |
{7: }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('works with old signs', function()
insert(example_test3)
feed 'gg'
n.command('sign define Oldsign text=x')
n.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' })
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2' })
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4' })
api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S5' })
screen:expect([[
{7:S4S1}^l1 |
{7:S2x }l2 |
{7:S5 }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('works with old signs (with range)', function()
insert(example_test3)
feed 'gg'
n.command('sign define Oldsign text=x')
n.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' })
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2' })
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S3', end_row = 4 })
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4' })
api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S5' })
screen:expect([[
{7:S4S3S1}^l1 |
{7:S3S2x }l2 |
{7:S5S3 }l3 |
{7:S3 }l4 |
{7:S3 }l5 |
{7: } |
{1:~ }|*3
|
]])
end)
it('can add a ranged sign (with start out of view)', function()
insert(example_test3)
command 'set signcolumn=yes:2'
feed 'gg'
feed '2<C-e>'
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'X', end_row = 3 })
screen:expect([[
{7:X }^l3 |
{7:X }l4 |
{7: }l5 |
{7: } |
{1:~ }|*5
|
]])
end)
it('can add lots of signs', function()
screen:try_resize(40, 10)
command 'normal 10oa b c d e f g h'
for i = 1, 10 do
api.nvim_buf_set_extmark(0, ns, i, 0, { end_col = 1, hl_group = 'Todo' })
api.nvim_buf_set_extmark(0, ns, i, 2, { end_col = 3, hl_group = 'Todo' })
api.nvim_buf_set_extmark(0, ns, i, 4, { end_col = 5, hl_group = 'Todo' })
api.nvim_buf_set_extmark(0, ns, i, 6, { end_col = 7, hl_group = 'Todo' })
api.nvim_buf_set_extmark(0, ns, i, 8, { end_col = 9, hl_group = 'Todo' })
api.nvim_buf_set_extmark(0, ns, i, 10, { end_col = 11, hl_group = 'Todo' })
api.nvim_buf_set_extmark(0, ns, i, 12, { end_col = 13, hl_group = 'Todo' })
api.nvim_buf_set_extmark(0, ns, i, 14, { end_col = 15, hl_group = 'Todo' })
api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'W' })
api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'X' })
api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'Y' })
api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'Z' })
end
screen:expect([[
{7:Z Y X W }{100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:h} |*8
{7:Z Y X W }{100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:^h} |
|
]])
end)
it('works with priority #19716', function()
screen:try_resize(20, 3)
insert(example_test3)
feed 'gg'
command('sign define Oldsign text=O3')
command([[exe 'sign place 42 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4', priority = 100 })
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S2', priority = 5 })
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S5', priority = 200 })
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', priority = 1 })
screen:expect([[
{7:S5S4O3S2S1}^l1 |
{7: }l2 |
|
]])
-- Check truncation works too
api.nvim_set_option_value('signcolumn', 'auto', {})
screen:expect([[
{7:S5}^l1 |
{7: }l2 |
|
]])
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([[
{7:O3O3O3O3O3O3O3O3O3}^ |
{1:~ }|
|
]])
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', priority = 1 })
screen:expect_unchanged()
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S5', priority = 200 })
screen:expect([[
{7:S5O3O3O3O3O3O3O3O3}^ |
{1:~ }|
|
]])
assert_alive()
end)
it('does not set signcolumn for signs without text', function()
screen:try_resize(20, 3)
api.nvim_set_option_value('signcolumn', 'auto', {})
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 0, -1, { number_hl_group = 'Error' })
screen:expect { grid = [[
^l1 |
l2 |
|
]] }
end)
it('correct width when removing multiple signs from sentinel line', function()
screen:try_resize(20, 4)
insert(example_test3)
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', end_row = 3 })
api.nvim_buf_set_extmark(0, ns, 1, -1, { invalidate = true, sign_text = 'S2' })
api.nvim_buf_set_extmark(0, ns, 1, -1, { invalidate = true, sign_text = 'S3' })
feed('2Gdd')
screen:expect([[
{7:S1}l1 |
{7:S1}^l3 |
{7:S1}l4 |
|
]])
end)
it('correct width with multiple overlapping signs', function()
screen:try_resize(20, 4)
insert(example_test3)
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' })
api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S2', end_row = 2 })
api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S3', end_row = 2 })
feed('gg')
local s1 = [[
{7:S2S1}^l1 |
{7:S3S2}l2 |
{7:S3S2}l3 |
|
]]
screen:expect(s1)
-- Correct width when :move'ing a line with signs
command('move2')
screen:expect([[
{7:S3 }l2 |
{7:S3S2S1}^l1 |
{7: }l3 |
|
]])
command('silent undo')
screen:expect { grid = s1 }
command('d')
screen:expect([[
{7:S3S2S1}^l2 |
{7:S3S2 }l3 |
{7: }l4 |
|
]])
command('d')
screen:expect([[
{7:S3S2S1}^l3 |
{7: }l4 |
{7: }l5 |
|
]])
end)
it('correct width when adding and removing multiple signs', function()
screen:try_resize(20, 4)
insert(example_test3)
feed('gg')
command([[
let ns = nvim_create_namespace('')
call nvim_buf_set_extmark(0, ns, 0, 0, {'sign_text':'S1', 'end_row':3})
let s1 = nvim_buf_set_extmark(0, ns, 2, 0, {'sign_text':'S2', 'end_row':4})
let s2 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
let s3 = nvim_buf_set_extmark(0, ns, 6, 0, {'sign_text':'S3'})
let s4 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
let s5 = nvim_buf_set_extmark(0, ns, 6, 0, {'sign_text':'S3'})
redraw!
call nvim_buf_del_extmark(0, ns, s2)
call nvim_buf_del_extmark(0, ns, s3)
call nvim_buf_del_extmark(0, ns, s4)
call nvim_buf_del_extmark(0, ns, s5)
redraw!
call nvim_buf_del_extmark(0, ns, s1)
]])
screen:expect([[
{7:S1}^l1 |
{7:S1}l2 |
{7:S1}l3 |
|
]])
end)
it('correct width when deleting lines', function()
screen:try_resize(20, 4)
insert(example_test3)
feed('gg')
command([[
let ns = nvim_create_namespace('')
call nvim_buf_set_extmark(0, ns, 4, 0, {'sign_text':'S1'})
call nvim_buf_set_extmark(0, ns, 4, 0, {'sign_text':'S2'})
let s3 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
call nvim_buf_del_extmark(0, ns, s3)
norm 4Gdd
]])
screen:expect([[
{7: }l3 |
{7:S2S1}l5 |
{7: }^ |
|
]])
end)
it('correct width when splitting lines with signs on different columns', function()
screen:try_resize(20, 4)
insert(example_test3)
feed('gg')
api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
api.nvim_buf_set_extmark(0, ns, 0, 1, { sign_text = 'S2' })
feed('a<cr><esc>')
screen:expect([[
{7:S1}l |
{7:S2}^1 |
{7: }l2 |
|
]])
end)
it('correct width after wiping a buffer', function()
screen:try_resize(20, 4)
insert(example_test3)
feed('gg')
local buf = api.nvim_get_current_buf()
api.nvim_buf_set_extmark(buf, ns, 0, 0, { sign_text = 'h' })
screen:expect([[
{7:h }^l1 |
{7: }l2 |
{7: }l3 |
|
]])
api.nvim_win_set_buf(0, api.nvim_create_buf(false, true))
api.nvim_buf_delete(buf, { unload = true, force = true })
api.nvim_buf_set_lines(buf, 0, -1, false, { '' })
api.nvim_win_set_buf(0, buf)
screen:expect { grid = [[
^ |
{1:~ }|*2
|
]] }
end)
it('correct width with moved marks before undo savepos', function()
screen:try_resize(20, 4)
insert(example_test3)
feed('gg')
exec_lua([[
local ns = vim.api.nvim_create_namespace('')
vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = 'S2' })
local s3 = vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S3' })
local s4 = vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S4' })
vim.schedule(function()
vim.cmd('silent d3')
vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { id = s3, sign_text = 'S3' })
vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { id = s4, sign_text = 'S4' })
vim.cmd('silent undo')
vim.api.nvim_buf_del_extmark(0, ns, s3)
end)
]])
screen:expect([[
{7:S1}^l1 |
{7:S2}l2 |
{7:S4}l3 |
|
]])
end)
it('no crash with sign after many marks #27137', function()
screen:try_resize(20, 4)
insert('a')
for _ = 0, 104 do
api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'Error', end_col = 1 })
end
api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
screen:expect([[
{7:S1}{9:^a} |
{1:~ }|*2
|
]])
end)
it('correct sort order with multiple namespaces and same id', function()
local ns2 = api.nvim_create_namespace('')
api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1', id = 1 })
api.nvim_buf_set_extmark(0, ns2, 0, 0, { sign_text = 'S2', id = 1 })
screen:expect([[
{7:S2S1}^ |
{1:~ }|*8
|
]])
end)
it('correct number of signs after deleting text (#27046)', function()
command('call setline(1, ["foo"]->repeat(31))')
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 0, sign_text = 'S1' })
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 0, end_col = 3, hl_group = 'Error' })
api.nvim_buf_set_extmark(0, ns, 9, 0, { end_row = 9, sign_text = 'S2' })
api.nvim_buf_set_extmark(0, ns, 9, 0, { end_row = 9, end_col = 3, hl_group = 'Error' })
api.nvim_buf_set_extmark(0, ns, 19, 0, { end_row = 19, sign_text = 'S3' })
api.nvim_buf_set_extmark(0, ns, 19, 0, { end_row = 19, end_col = 3, hl_group = 'Error' })
api.nvim_buf_set_extmark(0, ns, 29, 0, { end_row = 29, sign_text = 'S4' })
api.nvim_buf_set_extmark(0, ns, 29, 0, { end_row = 29, end_col = 3, hl_group = 'Error' })
api.nvim_buf_set_extmark(0, ns, 30, 0, { end_row = 30, sign_text = 'S5' })
api.nvim_buf_set_extmark(0, ns, 30, 0, { end_row = 30, end_col = 3, hl_group = 'Error' })
command('0d29')
screen:expect([[
{7:S4S3S2S1}{9:^foo} |
{7:S5 }{9:foo} |
{1:~ }|*7
29 fewer lines |
]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
it([[correct numberwidth with 'signcolumn' set to "number" #28984]], function()
command('set number numberwidth=1 signcolumn=number')
api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
screen:expect([[
{7:S1 }^ |
{1:~ }|*8
|
]])
api.nvim_buf_del_extmark(0, ns, 1)
screen:expect([[
{8:1 }^ |
{1:~ }|*8
|
]])
end)
it('supports emoji as signs', function()
insert(example_test3)
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = '🧑‍🌾' })
-- VS16 can change width of character
api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = '❤️' })
api.nvim_buf_set_extmark(0, ns, 3, 0, { sign_text = '❤' })
api.nvim_buf_set_extmark(0, ns, 4, 0, { sign_text = '❤x' })
screen:expect([[
{7: }^l1 |
{7:🧑‍🌾}l2 |
{7:❤️}l3 |
{7:❤ }l4 |
{7:❤x}l5 |
{7: } |
{1:~ }|*3
|
]])
eq("Invalid 'sign_text'", pcall_err(api.nvim_buf_set_extmark, 0, ns, 5, 0, { sign_text = '❤️x' }))
end)
it('auto signcolumn hides with invalidated sign', function()
api.nvim_set_option_value('signcolumn', 'auto', {})
api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1', invalidate = true })
feed('ia<cr>b<esc>dd')
screen:expect({
grid = [[
^a |
{1:~ }|*8
|
]],
})
end)
it('signcolumn correctly tracked with signs beyond eob and pair end before start', function()
api.nvim_set_option_value('signcolumn', 'auto:2', {})
api.nvim_set_option_value('filetype', 'lua', {})
api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' })
api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S1' })
api.nvim_set_hl(0, 'SignColumn', { link = 'Error' })
screen:expect([[
^foo |
bar |
{1:~ }|*7
|
]])
api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S2', end_row = 1 })
api.nvim_buf_set_lines(0, 0, -1, false, { '-- foo', '-- bar' })
api.nvim_buf_clear_namespace(0, ns, 0, -1)
screen:expect([[
^-- foo |
-- bar |
{1:~ }|*7
|
]])
assert_alive()
end)
end)
describe('decorations: virt_text', function()
local ns, screen ---@type integer, test.functional.ui.screen
before_each(function()
clear()
screen = Screen.new(50, 10)
ns = api.nvim_create_namespace('test')
end)
it('avoids regression in #17638', function()
command 'set number relativenumber'
command 'normal 4ohello'
command 'normal aVIRTUAL'
api.nvim_buf_set_extmark(0, ns, 2, 0, {
virt_text = { { 'hello', 'String' } },
virt_text_win_col = 20,
})
screen:expect {
grid = [[
{8: 4 } |
{8: 3 }hello |
{8: 2 }hello {26:hello} |
{8: 1 }hello |
{8:5 }helloVIRTUA^L |
{1:~ }|*4
|
]],
}
-- Trigger a screen update
feed('k')
screen:expect {
grid = [[
{8: 3 } |
{8: 2 }hello |
{8: 1 }hello {26:hello} |
{8:4 }hell^o |
{8: 1 }helloVIRTUAL |
{1:~ }|*4
|
]],
}
end)
it('redraws correctly when re-using extmark ids', function()
command 'normal 5ohello'
screen:expect {
grid = [[
|
hello |*4
hell^o |
{1:~ }|*3
|
]],
}
for row = 1, 5 do
api.nvim_buf_set_extmark(0, ns, row, 0, { id = 1, virt_text = { { 'world', 'Normal' } } })
end
screen:expect {
grid = [[
|
hello |*4
hell^o world |
{1:~ }|*3
|
]],
}
end)
it('redraws correctly when removing mark whose end ends up in front of start', function()
command('normal 5ohello')
api.nvim_buf_set_extmark(0, ns, 2, 0, { end_col = 1, virt_text = { { 'world', 'Normal' } } })
screen:expect([[
|
hello |
hello world |
hello |*2
hell^o |
{1:~ }|*3
|
]])
feed('3Gdd')
api.nvim_buf_clear_namespace(0, ns, 0, -1)
screen:expect([[
|
hello |
^hello |
hello |*2
{1:~ }|*4
|
]])
end)
end)
describe('decorations: window scoped', function()
local screen ---@type test.functional.ui.screen
local ns ---@type integer
local win_other ---@type integer
local url = 'https://example.com'
before_each(function()
clear()
screen = Screen.new(20, 10)
screen:add_extra_attr_ids {
[100] = { special = Screen.colors.Red, undercurl = true },
[101] = { url = 'https://example.com' },
}
ns = api.nvim_create_namespace 'test'
insert('12345')
win_other = api.nvim_open_win(0, false, {
col = 0,
row = 0,
width = 20,
height = 10,
relative = 'win',
style = 'minimal',
hide = true,
})
end)
local noextmarks = {
grid = [[
1234^5 |
{1:~ }|*8
|
]],
}
local function set_extmark(line, col, opts)
return api.nvim_buf_set_extmark(0, ns, line, col, opts)
end
it('hl_group', function()
set_extmark(0, 0, {
hl_group = 'Comment',
end_col = 3,
})
api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
]],
}
command 'split'
command 'only'
screen:expect(noextmarks)
end)
it('virt_text', function()
set_extmark(0, 0, {
virt_text = { { 'a', 'Comment' } },
virt_text_pos = 'eol',
})
set_extmark(0, 5, {
virt_text = { { 'b', 'Comment' } },
virt_text_pos = 'inline',
})
set_extmark(0, 1, {
virt_text = { { 'c', 'Comment' } },
virt_text_pos = 'overlay',
})
set_extmark(0, 1, {
virt_text = { { 'd', 'Comment' } },
virt_text_pos = 'right_align',
})
api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
1{18:c}34^5{18:b} {18:a} {18:d}|
{1:~ }|*8
|
]],
}
command 'split'
command 'only'
screen:expect(noextmarks)
api.nvim__ns_set(ns, { wins = {} })
screen:expect {
grid = [[
1{18:c}34^5{18:b} {18:a} {18:d}|
{1:~ }|*8
|
]],
}
end)
it('virt_lines', function()
set_extmark(0, 0, {
virt_lines = { { { 'a', 'Comment' } } },
})
api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
1234^5 |
{18:a} |
{1:~ }|*7
|
]],
}
command 'split'
command 'only'
screen:expect(noextmarks)
end)
it('redraws correctly with inline virt_text and wrapping', function()
set_extmark(0, 2, {
virt_text = { { ('b'):rep(18), 'Comment' } },
virt_text_pos = 'inline',
})
api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
12{18:bbbbbbbbbbbbbbbbbb}|
34^5 |
{1:~ }|*7
|
]],
}
api.nvim__ns_set(ns, { wins = { win_other } })
screen:expect(noextmarks)
end)
pending('sign_text', function()
-- TODO(altermo): The window signcolumn width is calculated wrongly (when `signcolumn=auto`)
-- This happens in function `win_redraw_signcols` on line containing `buf_meta_total(buf, kMTMetaSignText) > 0`
set_extmark(0, 0, {
sign_text = 'a',
sign_hl_group = 'Comment',
})
api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
a 1234^5 |
{2:~ }|*8
|
]],
}
command 'split'
command 'only'
screen:expect(noextmarks)
end)
it('statuscolumn hl group', function()
set_extmark(0, 0, {
number_hl_group = 'comment',
})
set_extmark(0, 0, {
line_hl_group = 'comment',
})
command 'set number'
api.nvim__ns_set(ns, { wins = { win_other } })
screen:expect {
grid = [[
{8: 1 }1234^5 |
{1:~ }|*8
|
]],
}
api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{18: 1 1234^5 }|
{1:~ }|*8
|
]],
}
command 'split'
command 'only'
screen:expect {
grid = [[
{8: 1 }1234^5 |
{1:~ }|*8
|
]],
}
end)
it('spell', function()
api.nvim_buf_set_lines(0, 0, -1, true, { 'aa' })
set_extmark(0, 0, {
spell = true,
end_col = 2,
})
command 'set spelloptions=noplainbuffer'
command 'set spell'
command 'syntax off'
screen:expect({ unchanged = true })
api.nvim__ns_set(ns, { wins = { win_other } })
screen:expect {
grid = [[
a^a |
{1:~ }|*8
|
]],
}
api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{100:a^a} |
{1:~ }|*8
|
]],
}
command 'split'
command 'only'
screen:expect {
grid = [[
a^a |
{1:~ }|*8
|
]],
}
end)
it('url', function()
set_extmark(0, 0, {
end_col = 3,
url = url,
})
api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{101:123}4^5 |
{1:~ }|*8
|
]],
}
command 'split'
command 'only'
screen:expect(noextmarks)
end)
it('change namespace scope', function()
set_extmark(0, 0, {
hl_group = 'Comment',
end_col = 3,
})
api.nvim__ns_set(ns, { wins = { 0 } })
eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
]],
}
command 'split'
command 'only'
screen:expect(noextmarks)
api.nvim__ns_set(ns, { wins = { 0 } })
eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
]],
}
local win_new = api.nvim_open_win(0, false, {
col = 0,
row = 0,
width = 20,
height = 10,
relative = 'win',
style = 'minimal',
hide = true,
})
api.nvim__ns_set(ns, { wins = { win_new } })
eq({ wins = { win_new } }, api.nvim__ns_get(ns))
screen:expect(noextmarks)
end)
it('namespace get works', function()
eq({ wins = {} }, api.nvim__ns_get(ns))
api.nvim__ns_set(ns, { wins = { 0 } })
eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
api.nvim__ns_set(ns, { wins = {} })
eq({ wins = {} }, api.nvim__ns_get(ns))
end)
it('remove window from namespace scope when deleted', function()
api.nvim__ns_set(ns, { wins = { 0 } })
eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
command 'split'
command 'only'
eq({ wins = {} }, api.nvim__ns_get(ns))
end)
end)