diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index da0fb9849a..1e702b1954 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -15,32 +15,36 @@ local eq = t.eq local assert_alive = n.assert_alive local pcall_err = t.pcall_err +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 before_each(function() clear() screen = Screen.new(40, 8) - 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}; - } + setup_screen(screen) end) local mulholland = [[ @@ -64,7 +68,7 @@ describe('decorations providers', function() ]]) .. [[ api.nvim_set_decoration_provider(_G.ns1, { on_start = on_do; on_buf = on_do; - on_win = on_do; on_line = 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 @@ -107,12 +111,19 @@ describe('decorations providers', function() { "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 }; } @@ -132,6 +143,7 @@ describe('decorations providers', function() { "buf", 1, 5 }; { "win", 1000, 1, 0, 6 }; { "line", 1000, 1, 6 }; + { "range", 1000, 1, 6, 0, 7, 0 }; { "end", 5 }; } end) @@ -199,9 +211,13 @@ describe('decorations providers', function() { "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 }; } @@ -694,6 +710,85 @@ describe('decorations providers', function() ]]) 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 [[ + p_min = { math.huge, math.huge } + p_max = { -math.huge, -math.huge } + function pos_gt(a, b) + return a[1] > b[1] or (a[1] == b[1] and a[2] > b[2]) + end + function pos_lt(a, b) + return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2]) + 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 pos_gt(p_min, b) then + p_min = b + end + if pos_lt(p_max, e) then + p_max = e + end + end + end + ]] + end + local function check(min, max) + local function pos_gt(a, b) + return a[1] > b[1] or (a[1] == b[1] and a[2] > b[2]) + end + local function pos_lt(a, b) + return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2]) + end + local p_min = exec_lua('return p_min') + assert(not pos_gt(p_min, min), + "minimum position " .. vim.inspect(p_min) + .. " should be before the first char") + local p_max = exec_lua('return p_max') + assert(not pos_lt(p_max, max), + "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 }) + end) + it('errors gracefully', function() insert(mulholland)