aboutsummaryrefslogtreecommitdiff
path: root/test/functional/ui
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/ui')
-rw-r--r--test/functional/ui/bufhl_spec.lua234
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua32
-rw-r--r--test/functional/ui/cmdline_spec.lua645
-rw-r--r--test/functional/ui/cursor_spec.lua52
-rw-r--r--test/functional/ui/embed_spec.lua81
-rw-r--r--test/functional/ui/fold_spec.lua8
-rw-r--r--test/functional/ui/highlight_spec.lua137
-rw-r--r--test/functional/ui/hlstate_spec.lua287
-rw-r--r--test/functional/ui/inccommand_spec.lua71
-rw-r--r--test/functional/ui/mode_spec.lua116
-rw-r--r--test/functional/ui/mouse_spec.lua31
-rw-r--r--test/functional/ui/options_spec.lua111
-rw-r--r--test/functional/ui/output_spec.lua33
-rw-r--r--test/functional/ui/popupmenu_spec.lua260
-rw-r--r--test/functional/ui/screen.lua800
-rw-r--r--test/functional/ui/screen_basic_spec.lua146
-rw-r--r--test/functional/ui/searchhl_spec.lua66
-rw-r--r--test/functional/ui/sign_spec.lua66
-rw-r--r--test/functional/ui/tabline_spec.lua12
-rw-r--r--test/functional/ui/wildmode_spec.lua81
20 files changed, 2444 insertions, 825 deletions
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 5b38921e50..95c9427399 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -3,7 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, neq = helpers.command, helpers.neq
-local curbufmeths = helpers.curbufmeths
+local curbufmeths, eq = helpers.curbufmeths, helpers.eq
describe('Buffer highlighting', function()
local screen
@@ -23,7 +23,13 @@ describe('Buffer highlighting', function()
[7] = {bold = true},
[8] = {underline = true, bold = true, foreground = Screen.colors.SlateBlue},
[9] = {foreground = Screen.colors.SlateBlue, underline = true},
- [10] = {foreground = Screen.colors.Red}
+ [10] = {foreground = Screen.colors.Red},
+ [11] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [12] = {foreground = Screen.colors.Blue1},
+ [13] = {background = Screen.colors.LightGrey},
+ [14] = {background = Screen.colors.Gray90},
+ [15] = {background = Screen.colors.Gray90, bold = true, foreground = Screen.colors.Brown},
+ [16] = {foreground = Screen.colors.Magenta, background = Screen.colors.Gray90},
})
end)
@@ -77,7 +83,7 @@ describe('Buffer highlighting', function()
|
]])
- clear_hl(-1, 0 , -1)
+ clear_hl(-1, 0, -1)
screen:expect([[
these are some lines |
^ |
@@ -275,4 +281,226 @@ describe('Buffer highlighting', function()
|
]])
end)
+
+ describe('virtual text annotations', function()
+ local set_virtual_text = curbufmeths.set_virtual_text
+ local id1, id2
+ before_each(function()
+ insert([[
+ 1 + 2
+ 3 +
+ x = 4]])
+ feed('O<esc>20A5, <esc>gg')
+ screen:expect([[
+ ^1 + 2 |
+ 3 + |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, |
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ id1 = set_virtual_text(0, 0, {{"=", "Statement"}, {" 3", "Number"}}, {})
+ set_virtual_text(id1, 1, {{"ERROR:", "ErrorMsg"}, {" invalid syntax"}}, {})
+ id2 = set_virtual_text(0, 2, {{"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."}}, {})
+ neq(id2, id1)
+
+ end)
+
+ it('works', function()
+ screen:expect([[
+ ^1 + 2 {3:=}{2: 3} |
+ 3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ clear_hl(id1, 0, -1)
+ screen:expect([[
+ ^1 + 2 |
+ 3 + |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ -- Handles doublewidth chars, leaving a space if truncating
+ -- in the middle of a char
+ eq(-1, set_virtual_text(-1, 1, {{"暗x事zz速野谷質結育副住新覚丸活解終事", "Comment"}}, {}))
+ screen:expect([[
+ ^1 + 2 |
+ 3 + {12:暗x事zz速野谷質結育副住新覚丸活解終 }|
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ feed("2Gx")
+ screen:expect([[
+ 1 + 2 |
+ ^ + {12:暗x事zz速野谷質結育副住新覚丸活解終事}|
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ feed("2Gdd")
+ screen:expect([[
+ 1 + 2 |
+ ^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('is not highlighted by visual selection', function()
+ feed("ggVG")
+ screen:expect([[
+ {13:1 + 2} {3:=}{2: 3} |
+ {13:3 +} {11:ERROR:} invalid syntax |
+ {13:5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}|
+ {13:, 5, 5, 5, 5, 5, 5, } Lorem ipsum dolor s|
+ ^x{13: = 4} |
+ {1:~ }|
+ {1:~ }|
+ {7:-- VISUAL LINE --} |
+ ]])
+
+ feed("<esc>")
+ screen:expect([[
+ 1 + 2 {3:=}{2: 3} |
+ 3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ ^x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ -- special case: empty line has extra eol highlight
+ feed("ggd$")
+ screen:expect([[
+ ^ {3:=}{2: 3} |
+ 3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ feed("jvk")
+ screen:expect([[
+ ^ {3:=}{2: 3} |
+ {13:3} + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ {7:-- VISUAL --} |
+ ]])
+
+ feed("o")
+ screen:expect([[
+ {13: }{3:=}{2: 3} |
+ ^3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ {7:-- VISUAL --} |
+ ]])
+ end)
+
+
+ it('works with listchars', function()
+ command("set list listchars+=eol:$")
+ screen:expect([[
+ ^1 + 2{1:$}{3:=}{2: 3} |
+ 3 +{1:$}{11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5,{1:-$}Lorem ipsum dolor s|
+ x = 4{1:$} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ clear_hl(-1, 0, -1)
+ screen:expect([[
+ ^1 + 2{1:$} |
+ 3 +{1:$} |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5,{1:-$} |
+ x = 4{1:$} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('works with cursorline', function()
+ command("set cursorline")
+
+ screen:expect([[
+ {14:^1 + 2 }{15:=}{16: 3}{14: }|
+ 3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ feed('j')
+ screen:expect([[
+ 1 + 2 {3:=}{2: 3} |
+ {14:^3 + }{11:ERROR:}{14: invalid syntax }|
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+
+ feed('j')
+ screen:expect([[
+ 1 + 2 {3:=}{2: 3} |
+ 3 + {11:ERROR:} invalid syntax |
+ {14:^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}|
+ {14:, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s}|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+ end)
+
end)
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index 5d9fffdf23..1568b7816e 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -32,7 +32,7 @@ before_each(function()
highlight RBP4 guibg=Blue
let g:NUM_LVLS = 4
function Redraw()
- redraw!
+ mode
return ''
endfunction
let g:id = ''
@@ -267,7 +267,7 @@ describe('Command-line coloring', function()
:echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
]])
redraw_input()
- screen:expect([[
+ screen:expect{grid=[[
|
{EOB:~ }|
{EOB:~ }|
@@ -276,7 +276,7 @@ describe('Command-line coloring', function()
{EOB:~ }|
{EOB:~ }|
:echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
- ]])
+ ]], reset=true}
end)
for _, func_part in ipairs({'', 'n', 'msg'}) do
it('disables :echo' .. func_part .. ' messages', function()
@@ -755,7 +755,7 @@ describe('Command-line coloring', function()
eq(1, meths.eval('1'))
end)
end)
-describe('Ex commands coloring support', function()
+describe('Ex commands coloring', function()
it('works', function()
meths.set_var('Nvim_color_cmdline', 'RainBowParens')
feed(':echo (((1)))')
@@ -831,7 +831,7 @@ describe('Ex commands coloring support', function()
|
]])
end)
- it('does not prevent mapping error from cancelling prompt', function()
+ it('mapping error does not cancel prompt', function()
command("cnoremap <expr> x execute('throw 42')[-1]")
feed(':#x')
screen:expect([[
@@ -846,27 +846,17 @@ describe('Ex commands coloring support', function()
]])
feed('<CR>')
screen:expect([[
- ^ |
- {EOB:~ }|
- {EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
- {EOB:~ }|
- |
+ :# |
+ {ERR:Error detected while processing :} |
+ {ERR:E605: Exception not caught: 42} |
+ {ERR:E749: empty buffer} |
+ {PE:Press ENTER or type command to continue}^ |
]])
feed('<CR>')
- screen:expect([[
- ^ |
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- |
- ]])
- eq('Error detected while processing :\nE605: Exception not caught: 42',
+ eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer',
meths.command_output('messages'))
end)
it('errors out when failing to get callback', function()
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 5ce49822e5..0ebb62f78f 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -1,23 +1,16 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq
+local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
-local ok = helpers.ok
local command = helpers.command
-describe('external cmdline', function()
+local function test_cmdline(linegrid)
local screen
- local last_level = 0
- local cmdline = {}
- local block = nil
- local wild_items = nil
- local wild_selected = nil
before_each(function()
clear()
- cmdline, block = {}, nil
screen = Screen.new(25, 5)
- screen:attach({rgb=true, ext_cmdline=true})
+ screen:attach({rgb=true, ext_cmdline=true, ext_linegrid=linegrid})
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {reverse = true},
@@ -25,138 +18,73 @@ describe('external cmdline', function()
[4] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[5] = {bold = true, foreground = Screen.colors.SeaGreen4},
})
- screen:set_on_event_handler(function(name, data)
- if name == "cmdline_show" then
- local content, pos, firstc, prompt, indent, level = unpack(data)
- ok(level > 0)
- cmdline[level] = {content=content, pos=pos, firstc=firstc,
- prompt=prompt, indent=indent}
- last_level = level
- elseif name == "cmdline_hide" then
- local level = data[1]
- cmdline[level] = nil
- elseif name == "cmdline_special_char" then
- local char, shift, level = unpack(data)
- cmdline[level].special = {char, shift}
- elseif name == "cmdline_pos" then
- local pos, level = unpack(data)
- cmdline[level].pos = pos
- elseif name == "cmdline_block_show" then
- block = data[1]
- elseif name == "cmdline_block_append" then
- block[#block+1] = data[1]
- elseif name == "cmdline_block_hide" then
- block = nil
- elseif name == "wildmenu_show" then
- wild_items = data[1]
- elseif name == "wildmenu_select" then
- wild_selected = data[1]
- elseif name == "wildmenu_hide" then
- wild_items, wild_selected = nil, nil
- end
- end)
end)
after_each(function()
screen:detach()
end)
- local function expect_cmdline(level, expected)
- local attr_ids = screen._default_attr_ids
- local attr_ignore = screen._default_attr_ignore
- local actual = ''
- for _, chunk in ipairs(cmdline[level] and cmdline[level].content or {}) do
- local attrs, text = chunk[1], chunk[2]
- if screen:_equal_attrs(attrs, {}) then
- actual = actual..text
- else
- local attr_id = screen:_get_attr_id(attr_ids, attr_ignore, attrs)
- actual = actual..'{' .. attr_id .. ':' .. text .. '}'
- end
- end
- eq(expected, actual)
- end
-
it('works', function()
feed(':')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq(1, last_level)
- eq({{
- content = { { {}, "" } },
- firstc = ":",
- indent = 0,
- pos = 0,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}}
feed('sign')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign"}},
+ pos = 4,
+ }}}
feed('<Left>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign" } },
- firstc = ":",
- indent = 0,
- pos = 3,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign"}},
+ pos = 3,
+ }}}
feed('<bs>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sin" } },
- firstc = ":",
- indent = 0,
- pos = 2,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sin"}},
+ pos = 2,
+ }}}
feed('<Esc>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
+ ]]}
end)
describe("redraws statusline on entering", function()
@@ -166,28 +94,32 @@ describe('external cmdline', function()
end)
it('from normal mode', function()
- feed(':')
- screen:expect([[
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {3:n }|
|
+ ]]}
+
+ feed(':')
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
- {3:c^ }|
+ {3:c }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "" } },
- firstc = ":",
- indent = 0,
- pos = 0,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}}
end)
it('but not with scrolled messages', function()
screen:try_resize(50,10)
feed(':echoerr doesnotexist<cr>')
- screen:expect([[
+ screen:expect{grid=[[
|
{1:~ }|
{1:~ }|
@@ -198,9 +130,9 @@ describe('external cmdline', function()
{4:E121: Undefined variable: doesnotexist} |
{4:E15: Invalid expression: doesnotexist} |
{5:Press ENTER or type command to continue}^ |
- ]])
+ ]]}
feed(':echoerr doesnotexist<cr>')
- screen:expect([[
+ screen:expect{grid=[[
|
{1:~ }|
{1:~ }|
@@ -211,10 +143,10 @@ describe('external cmdline', function()
{4:E121: Undefined variable: doesnotexist} |
{4:E15: Invalid expression: doesnotexist} |
{5:Press ENTER or type command to continue}^ |
- ]])
+ ]]}
feed(':echoerr doesnotexist<cr>')
- screen:expect([[
+ screen:expect{grid=[[
|
{1:~ }|
{3: }|
@@ -225,10 +157,10 @@ describe('external cmdline', function()
{4:E121: Undefined variable: doesnotexist} |
{4:E15: Invalid expression: doesnotexist} |
{5:Press ENTER or type command to continue}^ |
- ]])
+ ]]}
feed('<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
@@ -239,372 +171,308 @@ describe('external cmdline', function()
{1:~ }|
{3:n }|
|
- ]])
+ ]]}
end)
end)
it("works with input()", function()
feed(':call input("input", "default")<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "default" } },
- firstc = "",
- indent = 0,
- pos = 7,
- prompt = "input"
- }}, cmdline)
- end)
+ ]], cmdline={{
+ prompt = "input",
+ content = {{"default"}},
+ pos = 7,
+ }}}
+
feed('<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
-
+ ]]}
end)
it("works with special chars and nested cmdline", function()
feed(':xx<c-r>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "xx" } },
- firstc = ":",
- indent = 0,
- pos = 2,
- prompt = "",
- special = {'"', true},
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"xx"}},
+ pos = 2,
+ special = {'"', true},
+ }}}
feed('=')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "xx" } },
- firstc = ":",
- indent = 0,
- pos = 2,
- prompt = "",
- special = {'"', true},
- },{
- content = { { {}, "" } },
- firstc = "=",
- indent = 0,
- pos = 0,
- prompt = "",
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"xx"}},
+ pos = 2,
+ special = {'"', true},
+ }, {
+ firstc = "=",
+ content = {{""}},
+ pos = 0,
+ }}}
feed('1+2')
local expectation = {{
- content = { { {}, "xx" } },
- firstc = ":",
- indent = 0,
- pos = 2,
- prompt = "",
- special = {'"', true},
- },{
- content = {
- { {}, "1" },
- { {}, "+" },
- { {}, "2" },
- },
- firstc = "=",
- indent = 0,
- pos = 3,
- prompt = "",
- }}
- screen:expect([[
+ firstc = ":",
+ content = {{"xx"}},
+ pos = 2,
+ special = {'"', true},
+ }, {
+ firstc = "=",
+ content = {{"1"}, {"+"}, {"2"}},
+ pos = 3,
+ }}
+
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq(expectation, cmdline)
- end)
+ ]], cmdline=expectation}
-- erase information, so we check if it is retransmitted
- cmdline = {}
- command("redraw!")
- -- redraw! forgets cursor position. Be OK with that, as UI should indicate
- -- focus is at external cmdline anyway.
- screen:expect([[
- |
+ command("mode")
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
- ]], nil, nil, function()
- eq(expectation, cmdline)
- end)
+ |
+ ]], cmdline=expectation, reset=true}
feed('<cr>')
- screen:expect([[
- |
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
- ]], nil, nil, function()
- eq({{
- content = { { {}, "xx3" } },
- firstc = ":",
- indent = 0,
- pos = 3,
- prompt = "",
- }}, cmdline)
- end)
+ |
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"xx3"}},
+ pos = 3,
+ }}}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
+ ]]}
end)
it("works with function definitions", function()
feed(':function Foo()<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "" } },
- firstc = ":",
- indent = 2,
- pos = 0,
- prompt = "",
- }}, cmdline)
- eq({ { { {}, 'function Foo()'} } }, block)
- end)
+ ]], cmdline={{
+ indent = 2,
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}, cmdline_block = {
+ {{'function Foo()'}},
+ }}
feed('line1<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({ { { {}, 'function Foo()'} },
- { { {}, ' line1'} } }, block)
- end)
+ ]], cmdline={{
+ indent = 2,
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}, cmdline_block = {
+ {{'function Foo()'}},
+ {{' line1'}},
+ }}
- block = {}
- command("redraw!")
- screen:expect([[
- |
+ command("mode")
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
- ]], nil, nil, function()
- eq({ { { {}, 'function Foo()'} },
- { { {}, ' line1'} } }, block)
- end)
+ |
+ ]], cmdline={{
+ indent = 2,
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}, cmdline_block = {
+ {{'function Foo()'}},
+ {{' line1'}},
+ }, reset=true}
feed('endfunction<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq(nil, block)
- end)
+ ]]}
-- Try once more, to check buffer is reinitialized. #8007
feed(':function Bar()<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "" } },
- firstc = ":",
- indent = 2,
- pos = 0,
- prompt = "",
- }}, cmdline)
- eq({ { { {}, 'function Bar()'} } }, block)
- end)
+ ]], cmdline={{
+ indent = 2,
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}, cmdline_block = {
+ {{'function Bar()'}},
+ }}
feed('endfunction<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq(nil, block)
- end)
+ ]]}
+
end)
it("works with cmdline window", function()
feed(':make')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "make" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"make"}},
+ pos = 4,
+ }}}
feed('<c-f>')
- screen:expect([[
+ screen:expect{grid=[[
|
{2:[No Name] }|
{1::}make^ |
{3:[Command Line] }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
+ ]]}
-- nested cmdline
feed(':yank')
- screen:expect([[
+ screen:expect{grid=[[
|
{2:[No Name] }|
{1::}make^ |
{3:[Command Line] }|
|
- ]], nil, nil, function()
- eq({nil, {
- content = { { {}, "yank" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={nil, {
+ firstc = ":",
+ content = {{"yank"}},
+ pos = 4,
+ }}}
- cmdline = {}
- command("redraw!")
- screen:expect([[
+ command("mode")
+ screen:expect{grid=[[
|
{2:[No Name] }|
- {1::}make |
+ {1::}make^ |
{3:[Command Line] }|
- ^ |
- ]], nil, nil, function()
- eq({nil, {
- content = { { {}, "yank" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ |
+ ]], cmdline={nil, {
+ firstc = ":",
+ content = {{"yank"}},
+ pos = 4,
+ }}, reset=true}
feed("<c-c>")
- screen:expect([[
+ screen:expect{grid=[[
|
{2:[No Name] }|
{1::}make^ |
{3:[Command Line] }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
+ ]]}
feed("<c-c>")
- screen:expect([[
- |
+ screen:expect{grid=[[
+ ^ |
{2:[No Name] }|
- {1::}make^ |
+ {1::}make |
{3:[Command Line] }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "make" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"make"}},
+ pos = 4,
+ }}}
- cmdline = {}
command("redraw!")
- screen:expect([[
- |
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
- ]], nil, nil, function()
- eq({{
- content = { { {}, "make" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ |
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"make"}},
+ pos = 4,
+ }}}
end)
it('works with inputsecret()', function()
feed(":call inputsecret('secret:')<cr>abc123")
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "******" } },
- firstc = "",
- indent = 0,
- pos = 6,
- prompt = "secret:"
- }}, cmdline)
- end)
+ ]], cmdline={{
+ prompt = "secret:",
+ content = {{"******"}},
+ pos = 6,
+ }}}
end)
it('works with highlighted cmdline', function()
@@ -636,23 +504,21 @@ describe('external cmdline', function()
screen:set_default_attr_ids({
RBP1={background = Screen.colors.Red},
RBP2={background = Screen.colors.Yellow},
- RBP3={background = Screen.colors.Green},
- RBP4={background = Screen.colors.Blue},
EOB={bold = true, foreground = Screen.colors.Blue1},
- ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red},
- SK={foreground = Screen.colors.Blue},
- PE={bold = true, foreground = Screen.colors.SeaGreen4}
})
feed('<f5>(a(b)a)')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
|
- ]], nil, nil, function()
- expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}')
- end)
+ ]], cmdline={{
+ prompt = '>',
+ content = {{'(', 'RBP1'}, {'a'}, {'(', 'RBP2'}, {'b'},
+ { ')', 'RBP2'}, {'a'}, {')', 'RBP1'}},
+ pos = 7,
+ }}}
end)
it('works together with ext_wildmenu', function()
@@ -670,98 +536,73 @@ describe('external cmdline', function()
screen:set_option('ext_wildmenu', true)
feed(':sign <tab>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign define"} },
- firstc = ":",
- indent = 0,
- pos = 11,
- prompt = ""
- }}, cmdline)
- eq(expected, wild_items)
- eq(0, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign define"}},
+ pos = 11,
+ }}, wildmenu_items=expected, wildmenu_pos=0}
feed('<tab>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign jump"} },
- firstc = ":",
- indent = 0,
- pos = 9,
- prompt = ""
- }}, cmdline)
- eq(expected, wild_items)
- eq(1, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign jump"}},
+ pos = 9,
+ }}, wildmenu_items=expected, wildmenu_pos=1}
feed('<left><left>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign "} },
- firstc = ":",
- indent = 0,
- pos = 5,
- prompt = ""
- }}, cmdline)
- eq(expected, wild_items)
- eq(-1, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign "}},
+ pos = 5,
+ }}, wildmenu_items=expected, wildmenu_pos=-1}
feed('<right>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign define"} },
- firstc = ":",
- indent = 0,
- pos = 11,
- prompt = ""
- }}, cmdline)
- eq(expected, wild_items)
- eq(0, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign define"}},
+ pos = 11,
+ }}, wildmenu_items=expected, wildmenu_pos=0}
feed('a')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign definea"} },
- firstc = ":",
- indent = 0,
- pos = 12,
- prompt = ""
- }}, cmdline)
- eq(nil, wild_items)
- eq(nil, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign definea"}},
+ pos = 12,
+ }}}
end)
-end)
+end
+
+-- the representation of cmdline and cmdline_block contents changed with ext_linegrid
+-- (which uses indexed highlights) so make sure to test both
+describe('ui/ext_cmdline', function() test_cmdline(true) end)
+describe('ui/ext_cmdline (legacy highlights)', function() test_cmdline(false) end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 812c095add..3e0370db14 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -28,6 +28,8 @@ describe('ui/cursor', function()
name = 'normal',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'n' },
[2] = {
@@ -39,6 +41,8 @@ describe('ui/cursor', function()
name = 'visual',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'v' },
[3] = {
@@ -50,6 +54,8 @@ describe('ui/cursor', function()
name = 'insert',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'i' },
[4] = {
@@ -61,6 +67,8 @@ describe('ui/cursor', function()
name = 'replace',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'r' },
[5] = {
@@ -72,6 +80,8 @@ describe('ui/cursor', function()
name = 'cmdline_normal',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'c' },
[6] = {
@@ -83,6 +93,8 @@ describe('ui/cursor', function()
name = 'cmdline_insert',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'ci' },
[7] = {
@@ -94,6 +106,8 @@ describe('ui/cursor', function()
name = 'cmdline_replace',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'cr' },
[8] = {
@@ -105,6 +119,8 @@ describe('ui/cursor', function()
name = 'operator',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'o' },
[9] = {
@@ -116,6 +132,8 @@ describe('ui/cursor', function()
name = 'visual_select',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 've' },
[10] = {
@@ -155,6 +173,8 @@ describe('ui/cursor', function()
name = 'showmatch',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
short_name = 'sm' },
}
@@ -168,17 +188,18 @@ describe('ui/cursor', function()
-- Event is published ONLY if the cursor style changed.
screen._mode_info = nil
command("echo 'test'")
- screen:expect([[
+ screen:expect{grid=[[
^ |
~ |
~ |
~ |
test |
- ]], nil, nil, function()
+ ]], condition=function()
eq(nil, screen._mode_info)
- end)
+ end}
-- Change the cursor style.
+ helpers.command('hi Cursor guibg=DarkGray')
helpers.command('set guicursor=n-v-c:block,i-ci-ve:ver25,r-cr-o:hor20'
..',a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor'
..',sm:block-blinkwait175-blinkoff150-blinkon175')
@@ -194,7 +215,10 @@ describe('ui/cursor', function()
if m.blinkoff then m.blinkoff = 400 end
if m.blinkwait then m.blinkwait = 700 end
end
- if m.hl_id then m.hl_id = 49 end
+ if m.hl_id then
+ m.hl_id = 49
+ m.attr = {background = Screen.colors.DarkGray}
+ end
if m.id_lm then m.id_lm = 50 end
end
@@ -205,6 +229,26 @@ describe('ui/cursor', function()
eq('normal', screen.mode)
end)
+ -- Change hl groups only, should update the styles
+ helpers.command('hi Cursor guibg=Red')
+ helpers.command('hi lCursor guibg=Green')
+
+ -- Update the expected values.
+ for _, m in ipairs(expected_mode_info) do
+ if m.hl_id then
+ m.attr = {background = Screen.colors.Red}
+ end
+ if m.id_lm then
+ m.attr_lm = {background = Screen.colors.Green}
+ end
+ end
+ -- Assert the new expectation.
+ screen:expect(function()
+ eq(expected_mode_info, screen._mode_info)
+ eq(true, screen._cursor_style_enabled)
+ eq('normal', screen.mode)
+ end)
+
-- Another cursor style.
meths.set_option('guicursor', 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173'
..',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42')
diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua
new file mode 100644
index 0000000000..4fc93c3b63
--- /dev/null
+++ b/test/functional/ui/embed_spec.lua
@@ -0,0 +1,81 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local feed = helpers.feed
+local eq = helpers.eq
+local clear = helpers.clear
+
+local function test_embed(ext_linegrid)
+ local screen
+ local function startup(...)
+ clear{headless=false, args={...}}
+
+ -- attach immediately after startup, for early UI
+ screen = Screen.new(60, 8)
+ screen:attach{ext_linegrid=ext_linegrid}
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [2] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [3] = {bold = true, foreground = Screen.colors.Blue1},
+ })
+ end
+
+ it('can display errors', function()
+ startup('--cmd', 'echoerr invalid+')
+ screen:expect([[
+ |
+ |
+ |
+ |
+ Error detected while processing pre-vimrc command line: |
+ E121: Undefined variable: invalid |
+ E15: Invalid expression: invalid+ |
+ Press ENTER or type command to continue^ |
+ ]])
+
+ feed('<cr>')
+ screen:expect([[
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+
+ it("doesn't erase output when setting color scheme", function()
+ startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"')
+ screen:expect([[
+ |
+ |
+ |
+ |
+ Error detected while processing pre-vimrc command line: |
+ foo |
+ {1:bar} |
+ {2:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+
+ it("doesn't erase output when setting Normal colors", function()
+ startup('--cmd', 'echoerr "foo"', '--cmd', 'hi Normal guibg=Green', '--cmd', 'echoerr "bar"')
+ screen:expect{grid=[[
+ |
+ |
+ |
+ |
+ Error detected while processing pre-vimrc command line: |
+ foo |
+ bar |
+ Press ENTER or type command to continue^ |
+ ]], condition=function()
+ eq(Screen.colors.Green, screen.default_colors.rgb_bg)
+ end}
+ end)
+end
+
+describe('--embed UI on startup (ext_linegrid=true)', function() test_embed(true) end)
+describe('--embed UI on startup (ext_linegrid=false)', function() test_embed(false) end)
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 9c5a59b58d..39a5c10bb7 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -65,7 +65,7 @@ describe("folded lines", function()
{1:~ }|
{1:~ }|
{1:~ }|
- |
+ :set noarabicshape |
]])
feed_command("set number foldcolumn=2")
@@ -114,7 +114,7 @@ describe("folded lines", function()
{1: ~}|
{1: ~}|
{1: ~}|
- |
+ :set arabicshape |
]])
feed('zo')
@@ -126,7 +126,7 @@ describe("folded lines", function()
{1: ~}|
{1: ~}|
{1: ~}|
- |
+ :set arabicshape |
]])
feed_command('set noarabicshape')
@@ -138,7 +138,7 @@ describe("folded lines", function()
{1: ~}|
{1: ~}|
{1: ~}|
- |
+ :set noarabicshape |
]])
end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index b46a6c1e46..55fc343e4c 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -40,24 +40,24 @@ describe('highlight: `:syntax manual`', function()
end)
it("works with buffer switch and 'hidden'", function()
- feed_command('e tmp1.vim')
- feed_command('e Xtest-functional-ui-highlight.tmp.vim')
- feed_command('filetype on')
- feed_command('syntax manual')
- feed_command('set ft=vim')
- feed_command('set syntax=ON')
+ command('e tmp1.vim')
+ command('e Xtest-functional-ui-highlight.tmp.vim')
+ command('filetype on')
+ command('syntax manual')
+ command('set ft=vim')
+ command('set syntax=ON')
feed('iecho 1<esc>0')
- feed_command('set hidden')
- feed_command('w')
- feed_command('bn')
+ command('set hidden')
+ command('w')
+ command('bn')
feed_command('bp')
screen:expect([[
{1:^echo} 1 |
{0:~ }|
{0:~ }|
{0:~ }|
- <f 1 --100%-- col 1 |
+ :bp |
]])
end)
@@ -122,7 +122,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{2:[No Name] }|
- |
+ :vsp |
]])
-- navigate to verify that the attributes are properly moved
feed('<c-w>j')
@@ -140,7 +140,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{1:[No Name] }|
- |
+ :vsp |
]])
-- note that when moving to a window with small width nvim will increase
-- the width of the new active window at the expense of a inactive window
@@ -160,7 +160,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{2:[No Name] }|
- |
+ :vsp |
]])
feed('<c-w>l')
screen:expect([[
@@ -177,7 +177,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{2:[No Name] }|
- |
+ :vsp |
]])
feed('<c-w>h<c-w>h')
screen:expect([[
@@ -194,7 +194,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{2:[No Name] }|
- |
+ :vsp |
]])
end)
@@ -677,6 +677,7 @@ end)
describe('CursorLine highlight', function()
before_each(clear)
+
it('overridden by Error, ColorColumn if fg not set', function()
local screen = Screen.new(50,5)
screen:set_default_attr_ids({
@@ -690,9 +691,9 @@ describe('CursorLine highlight', function()
})
screen:attach()
- feed_command('filetype on')
- feed_command('syntax on')
- feed_command('set cursorline ft=json')
+ command('filetype on')
+ command('syntax on')
+ command('set cursorline ft=json')
feed('i{<cr>"a" : abc // 10;<cr>}<cr><esc>')
screen:expect([[
{1:{} |
@@ -702,7 +703,7 @@ describe('CursorLine highlight', function()
|
]])
- feed_command('set colorcolumn=3')
+ command('set colorcolumn=3')
feed('i <esc>')
screen:expect([[
{1:{} {7: } |
@@ -712,6 +713,62 @@ describe('CursorLine highlight', function()
|
]])
end)
+
+ it('with split-windows in diff-mode', function()
+ local screen = Screen.new(50,12)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [2] = {bold = true, background = Screen.colors.Red},
+ [3] = {background = Screen.colors.LightMagenta},
+ [4] = {reverse = true},
+ [5] = {background = Screen.colors.LightBlue},
+ [6] = {background = Screen.colors.LightCyan1, bold = true, foreground = Screen.colors.Blue1},
+ [7] = {background = Screen.colors.Red, foreground = Screen.colors.White},
+ [8] = {bold = true, foreground = Screen.colors.Blue1},
+ [9] = {bold = true, reverse = true},
+ [10] = {bold = true},
+ })
+ screen:attach()
+
+ command('hi CursorLine ctermbg=red ctermfg=white guibg=red guifg=white')
+ command('set cursorline')
+ feed('iline 1 some text<cr>line 2 more text<cr>extra line!<cr>extra line!<cr>last line ...<cr>')
+ feed('<esc>gg')
+ command('vsplit')
+ command('enew')
+ feed('iline 1 some text<cr>line 2 moRe text!<cr>extra line!<cr>extra line!<cr>extra line!<cr>last line ...<cr>')
+ feed('<esc>gg')
+ command('windo diffthis')
+ screen:expect([[
+ {1: }{7:line 1 some text }{4:│}{1: }{7:^line 1 some text }|
+ {1: }{3:line 2 mo}{2:Re text!}{3: }{4:│}{1: }{3:line 2 mo}{2:re text}{3: }|
+ {1: }{5:extra line! }{4:│}{1: }{6:----------------------}|
+ {1: }extra line! {4:│}{1: }extra line! |
+ {1: }extra line! {4:│}{1: }extra line! |
+ {1: }last line ... {4:│}{1: }last line ... |
+ {1: } {4:│}{1: } |
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {4:[No Name] [+] }{9:[No Name] [+] }|
+ |
+ ]])
+ feed('jjjjj')
+ screen:expect([[
+ {1: }line 1 some text {4:│}{1: }line 1 some text |
+ {1: }{3:line 2 mo}{2:Re text!}{3: }{4:│}{1: }{3:line 2 mo}{2:re text}{3: }|
+ {1: }{5:extra line! }{4:│}{1: }{6:----------------------}|
+ {1: }extra line! {4:│}{1: }extra line! |
+ {1: }extra line! {4:│}{1: }extra line! |
+ {1: }last line ... {4:│}{1: }last line ... |
+ {1: }{7: }{4:│}{1: }{7:^ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {4:[No Name] [+] }{9:[No Name] [+] }|
+ |
+ ]])
+ end)
end)
@@ -834,7 +891,7 @@ describe("'winhighlight' highlight", function()
{1:a^a }|
{2:~ }|
{2:~ }|
- {11:[No Name] [+] }|
+ {3:[No Name] [+] }|
aa |
{0:~ }|
{4:[No Name] [+] }|
@@ -846,7 +903,7 @@ describe("'winhighlight' highlight", function()
{1:^ }|
{2:~ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
aa |
{0:~ }|
{4:[No Name] [+] }|
@@ -870,7 +927,7 @@ describe("'winhighlight' highlight", function()
eq('Vim(set):E474: Invalid argument: winhl=xxx:yyy',
exc_exec("set winhl=xxx:yyy"))
eq('Normal:Background1', eval('&winhl'))
- screen:expect([[
+ screen:expect{grid=[[
{1:^ }|
{2:~ }|
{2:~ }|
@@ -879,7 +936,7 @@ describe("'winhighlight' highlight", function()
{2:~ }|
{2:~ }|
|
- ]])
+ ]], unchanged=true}
end)
@@ -891,7 +948,7 @@ describe("'winhighlight' highlight", function()
{1:a^a }|
{2:~ }|
{2:~ }|
- {11:[No Name] [+] }|
+ {3:[No Name] [+] }|
aa |
{0:~ }|
{4:[No Name] [+] }|
@@ -915,11 +972,11 @@ describe("'winhighlight' highlight", function()
{1:^aa }|
{2:~ }|
{2:~ }|
- {11:[No Name] [+] }|
+ {3:[No Name] [+] }|
aa |
{0:~ }|
{4:[No Name] [+] }|
- <f 1 --100%-- col 1 |
+ |
]])
end)
@@ -931,10 +988,10 @@ describe("'winhighlight' highlight", function()
{1:^ }|
{2:~ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
{5: }|
{6:~ }|
- {12:[No Name] }|
+ {4:[No Name] }|
|
]])
@@ -943,10 +1000,10 @@ describe("'winhighlight' highlight", function()
{5: }|
{6:~ }|
{6:~ }|
- {12:[No Name] }|
+ {4:[No Name] }|
{1:^ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
|
]])
@@ -955,10 +1012,10 @@ describe("'winhighlight' highlight", function()
{1:^ }|
{2:~ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
{5: }|
{6:~ }|
- {12:[No Name] }|
+ {4:[No Name] }|
|
]])
end)
@@ -974,7 +1031,7 @@ describe("'winhighlight' highlight", function()
{3:[No Name] }|
{7: }|
{8:~ }|
- {13:[No Name] }|
+ {4:[No Name] }|
|
]])
@@ -983,7 +1040,7 @@ describe("'winhighlight' highlight", function()
{7: }|
{8:~ }|
{8:~ }|
- {13:[No Name] }|
+ {4:[No Name] }|
^ |
{0:~ }|
{3:[No Name] }|
@@ -997,10 +1054,10 @@ describe("'winhighlight' highlight", function()
{7: }|
{8:~ }|
{8:~ }|
- {13:[No Name] }|
+ {4:[No Name] }|
{1:^ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
|
]])
@@ -1012,7 +1069,7 @@ describe("'winhighlight' highlight", function()
{3:[No Name] }|
{1: }|
{2:~ }|
- {14:[No Name] }|
+ {4:[No Name] }|
|
]])
@@ -1022,10 +1079,10 @@ describe("'winhighlight' highlight", function()
{7: }|
{8:~ }|
{8:~ }|
- {13:[No Name] }|
+ {4:[No Name] }|
{1:^ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
|
]])
@@ -1037,7 +1094,7 @@ describe("'winhighlight' highlight", function()
{3:[No Name] }|
{5: }|
{6:~ }|
- {12:[No Name] }|
+ {4:[No Name] }|
|
]])
end)
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
new file mode 100644
index 0000000000..672af5fb22
--- /dev/null
+++ b/test/functional/ui/hlstate_spec.lua
@@ -0,0 +1,287 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local clear, insert = helpers.clear, helpers.insert
+local command = helpers.command
+local meths = helpers.meths
+local iswin = helpers.iswin
+local nvim_dir = helpers.nvim_dir
+local thelpers = require('test.functional.terminal.helpers')
+
+describe('ext_hlstate detailed highlights', function()
+ local screen
+
+ before_each(function()
+ clear()
+ command('syntax on')
+ screen = Screen.new(40, 8)
+ screen:attach({ext_hlstate=true})
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+
+ it('work with combined UI and syntax highlights', function()
+ insert([[
+ these are some lines
+ with colorful text]])
+ meths.buf_add_highlight(0, -1, "String", 0 , 10, 14)
+ meths.buf_add_highlight(0, -1, "Statement", 1 , 5, -1)
+ command("/th co")
+
+ screen:expect([[
+ these are {1:some} lines |
+ ^wi{2:th }{4:co}{3:lorful text} |
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {6:search hit BOTTOM, continuing at TOP} |
+ ]], {
+ [1] = {{foreground = Screen.colors.Magenta},
+ {{hi_name = "Constant", kind = "syntax"}}},
+ [2] = {{background = Screen.colors.Yellow},
+ {{hi_name = "Search", ui_name = "Search", kind = "ui"}}},
+ [3] = {{bold = true, foreground = Screen.colors.Brown},
+ {{hi_name = "Statement", kind = "syntax"}}},
+ [4] = {{bold = true, background = Screen.colors.Yellow, foreground = Screen.colors.Brown}, {3, 2}},
+ [5] = {{bold = true, foreground = Screen.colors.Blue1},
+ {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ [6] = {{foreground = Screen.colors.Red},
+ {{hi_name = "WarningMsg", ui_name = "WarningMsg", kind = "ui"}}},
+ })
+ end)
+
+ it('work with cleared UI highlights', function()
+ screen:set_default_attr_ids({
+ [1] = {{}, {{hi_name = "VertSplit", ui_name = "VertSplit", kind = "ui"}}},
+ [2] = {{bold = true, foreground = Screen.colors.Blue1},
+ {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ [3] = {{bold = true, reverse = true},
+ {{hi_name = "StatusLine", ui_name = "StatusLine", kind = "ui"}}} ,
+ [4] = {{reverse = true},
+ {{hi_name = "StatusLineNC", ui_name = "StatusLineNC" , kind = "ui"}}},
+ [5] = {{}, {{hi_name = "StatusLine", ui_name = "StatusLine", kind = "ui"}}},
+ [6] = {{}, {{hi_name = "StatusLineNC", ui_name = "StatusLineNC", kind = "ui"}}},
+ })
+ command("hi clear VertSplit")
+ command("vsplit")
+
+ screen:expect([[
+ ^ {1:│} |
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {3:[No Name] }{4:[No Name] }|
+ |
+ ]])
+
+ command("hi clear StatusLine | hi clear StatuslineNC")
+ screen:expect([[
+ ^ {1:│} |
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {5:[No Name] }{6:[No Name] }|
+ |
+ ]])
+
+ -- redrawing is done even if visible highlights didn't change
+ command("wincmd w")
+ screen:expect([[
+ {1:│}^ |
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {6:[No Name] }{5:[No Name] }|
+ |
+ ]])
+
+ end)
+
+ it("work with window-local highlights", function()
+ screen:set_default_attr_ids({
+ [1] = {{foreground = Screen.colors.Brown}, {{hi_name = "LineNr", ui_name = "LineNr", kind = "ui"}}},
+ [2] = {{bold = true, foreground = Screen.colors.Blue1}, {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ [3] = {{bold = true, reverse = true}, {{hi_name = "StatusLine", ui_name = "StatusLine", kind = "ui"}}},
+ [4] = {{reverse = true}, {{hi_name = "StatusLineNC", ui_name = "StatusLineNC", kind = "ui"}}},
+ [5] = {{background = Screen.colors.Red, foreground = Screen.colors.Grey100}, {{hi_name = "ErrorMsg", ui_name = "LineNr", kind = "ui"}}},
+ [6] = {{bold = true, reverse = true}, {{hi_name = "MsgSeparator", ui_name = "Normal", kind = "ui"}}},
+ [7] = {{foreground = Screen.colors.Brown, bold = true, reverse = true}, {6, 1}},
+ [8] = {{foreground = Screen.colors.Blue1, bold = true, reverse = true}, {6, 2}},
+ [9] = {{bold = true, foreground = Screen.colors.Brown}, {{hi_name = "Statement", ui_name = "NormalNC", kind = "ui"}}},
+ [10] = {{bold = true, foreground = Screen.colors.Brown}, {9, 1}},
+ [11] = {{bold = true, foreground = Screen.colors.Blue1}, {9, 2}}
+ })
+
+ command("set number")
+ command("split")
+ -- NormalNC is not applied if not set, to avoid spurious redraws
+ screen:expect([[
+ {1: 1 }^ |
+ {2:~ }|
+ {2:~ }|
+ {3:[No Name] }|
+ {1: 1 } |
+ {2:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+
+ command("set winhl=LineNr:ErrorMsg")
+ screen:expect([[
+ {5: 1 }^ |
+ {2:~ }|
+ {2:~ }|
+ {3:[No Name] }|
+ {1: 1 } |
+ {2:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+
+ command("set winhl=Normal:MsgSeparator,NormalNC:Statement")
+ screen:expect([[
+ {7: 1 }{6:^ }|
+ {8:~ }|
+ {8:~ }|
+ {3:[No Name] }|
+ {1: 1 } |
+ {2:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+
+ command("wincmd w")
+ screen:expect([[
+ {10: 1 }{9: }|
+ {11:~ }|
+ {11:~ }|
+ {4:[No Name] }|
+ {1: 1 }^ |
+ {2:~ }|
+ {3:[No Name] }|
+ |
+ ]])
+ end)
+
+ it("work with :terminal", function()
+ screen:set_default_attr_ids({
+ [1] = {{}, {{hi_name = "TermCursorNC", ui_name = "TermCursorNC", kind = "ui"}}},
+ [2] = {{special = Screen.colors.Grey0, foreground = 52479}, {{kind = "term"}}},
+ [3] = {{special = Screen.colors.Grey0, bold = true, foreground = 52479}, {{kind = "term"}}},
+ [4] = {{special = Screen.colors.Grey0, foreground = 52479}, {2, 1}},
+ [5] = {{special = Screen.colors.Grey0, foreground = 4259839}, {{kind = "term"}}},
+ [6] = {{special = Screen.colors.Grey0, foreground = 4259839}, {5, 1}},
+ })
+ command('enew | call termopen(["'..nvim_dir..'/tty-test"])')
+ screen:expect([[
+ ^tty ready |
+ {1: } |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]])
+
+ thelpers.feed_data('x ')
+ thelpers.set_fg(45)
+ thelpers.feed_data('y ')
+ thelpers.set_bold()
+ thelpers.feed_data('z\n')
+ -- TODO(bfredl): check if this distinction makes sense
+ if iswin() then
+ screen:expect([[
+ ^tty ready |
+ x {5:y z} |
+ {1: } |
+ |
+ |
+ |
+ |
+ |
+ ]])
+ else
+ screen:expect([[
+ ^tty ready |
+ x {2:y }{3:z} |
+ {1: } |
+ |
+ |
+ |
+ |
+ |
+ ]])
+ end
+
+ thelpers.feed_termcode("[A")
+ thelpers.feed_termcode("[2C")
+ if iswin() then
+ screen:expect([[
+ ^tty ready |
+ x {6:y}{5: z} |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]])
+ else
+ screen:expect([[
+ ^tty ready |
+ x {4:y}{2: }{3:z} |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]])
+ end
+ end)
+
+ it("can use independent cterm and rgb colors", function()
+ -- tell test module to save all attributes (doesn't change nvim options)
+ screen:set_hlstate_cterm(true)
+
+ screen:set_default_attr_ids({
+ [1] = {{bold = true, foreground = Screen.colors.Blue1}, {foreground = 12}, {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ [2] = {{reverse = true, foreground = Screen.colors.Red}, {foreground = 10, italic=true}, {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ })
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ command("hi NonText guifg=Red gui=reverse ctermfg=Green cterm=italic")
+ screen:expect([[
+ ^ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+
+ end)
+end)
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 9cc697a4b6..bb6cb543ed 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -495,6 +495,18 @@ describe(":substitute, 'inccommand' preserves undo", function()
for _, case in pairs(cases) do
clear()
common_setup(screen, case, default_text)
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ ^ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ |
+ ]])
feed_command("set undolevels=1")
feed("1G0")
@@ -745,20 +757,35 @@ describe(":substitute, inccommand=split", function()
it("shows preview when cmd modifiers are present", function()
-- one modifier
feed(':keeppatterns %s/tw/to')
- screen:expect([[{12:to}o lines]], nil, nil, nil, true)
+ screen:expect{any=[[{12:to}o lines]]}
feed('<Esc>')
- screen:expect([[two lines]], nil, nil, nil, true)
+ screen:expect{any=[[two lines]]}
-- multiple modifiers
feed(':keeppatterns silent %s/tw/to')
- screen:expect([[{12:to}o lines]], nil, nil, nil, true)
+ screen:expect{any=[[{12:to}o lines]]}
feed('<Esc>')
- screen:expect([[two lines]], nil, nil, nil, true)
+ screen:expect{any=[[two lines]]}
-- non-modifier prefix
feed(':silent tabedit %s/tw/to')
- screen:expect([[two lines]], nil, nil, nil, true)
- feed('<Esc>')
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :silent tabedit %s/tw/to^ |
+ ]])
end)
it('shows split window when typing the pattern', function()
@@ -866,7 +893,6 @@ describe(":substitute, inccommand=split", function()
it('does not show split window for :s/', function()
feed("2gg")
feed(":s/tw")
- screen:sleep(1)
screen:expect([[
Inc substitution on |
{12:tw}o lines |
@@ -1222,20 +1248,30 @@ describe("inccommand=nosplit", function()
it("shows preview when cmd modifiers are present", function()
-- one modifier
feed(':keeppatterns %s/tw/to')
- screen:expect([[{12:to}o lines]], nil, nil, nil, true)
+ screen:expect{any=[[{12:to}o lines]]}
feed('<Esc>')
- screen:expect([[two lines]], nil, nil, nil, true)
+ screen:expect{any=[[two lines]]}
-- multiple modifiers
feed(':keeppatterns silent %s/tw/to')
- screen:expect([[{12:to}o lines]], nil, nil, nil, true)
+ screen:expect{any=[[{12:to}o lines]]}
feed('<Esc>')
- screen:expect([[two lines]], nil, nil, nil, true)
+ screen:expect{any=[[two lines]]}
-- non-modifier prefix
feed(':silent tabedit %s/tw/to')
- screen:expect([[two lines]], nil, nil, nil, true)
- feed('<Esc>')
+ screen:expect([[
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :silent tabedit %s/t|
+ w/to^ |
+ ]])
end)
it("does not show window after toggling :set inccommand", function()
@@ -1503,7 +1539,7 @@ describe("'inccommand' and :cnoremap", function()
end
end)
- it('does not work with a failing mapping', function()
+ it('still works with a broken mapping', function()
for _, case in pairs(cases) do
refresh(case)
feed_command("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
@@ -1512,7 +1548,10 @@ describe("'inccommand' and :cnoremap", function()
-- error thrown b/c of the mapping
neq(nil, eval('v:errmsg'):find('^E523:'))
- expect(default_text)
+ expect([[
+ Inc substitution on
+ toxo lines
+ ]])
end
end)
@@ -2473,7 +2512,7 @@ describe(":substitute", function()
end)
it(':substitute with inccommand during :terminal activity', function()
- retry(2, nil, function()
+ retry(2, 40000, function()
local screen = Screen.new(30,15)
clear()
diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua
index f0cedfeeb5..f6b3c1c3c9 100644
--- a/test/functional/ui/mode_spec.lua
+++ b/test/functional/ui/mode_spec.lua
@@ -21,207 +21,169 @@ describe('ui mode_change event', function()
end)
it('works in normal mode', function()
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
feed('d')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("operator", screen.mode)
- end)
+ ]], mode="operator"}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
end)
it('works in insert mode', function()
feed('i')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
- ]],nil,nil,function ()
- eq("insert", screen.mode)
- end)
+ ]], mode="insert"}
feed('word<esc>')
- screen:expect([[
+ screen:expect{grid=[[
wor^d |
{0:~ }|
{0:~ }|
|
- ]], nil, nil, function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
command("set showmatch")
eq(eval('&matchtime'), 5) -- tenths of seconds
feed('a(stuff')
- screen:expect([[
+ screen:expect{grid=[[
word(stuff^ |
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
- ]], nil, nil, function ()
- eq("insert", screen.mode)
- end)
+ ]], mode="insert"}
feed(')')
- screen:expect([[
+ screen:expect{grid=[[
word^(stuff) |
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
- ]], nil, nil, function ()
- eq("showmatch", screen.mode)
- end)
+ ]], mode="showmatch"}
screen:sleep(400)
- screen:expect([[
+ screen:expect{grid=[[
word(stuff)^ |
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
- ]], nil, nil, function ()
- eq("insert", screen.mode)
- end)
+ ]], mode="insert"}
end)
it('works in replace mode', function()
feed('R')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
{2:-- REPLACE --} |
- ]], nil, nil, function ()
- eq("replace", screen.mode)
- end)
+ ]], mode="replace"}
feed('word<esc>')
- screen:expect([[
+ screen:expect{grid=[[
wor^d |
{0:~ }|
{0:~ }|
|
- ]], nil, nil, function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
end)
it('works in cmdline mode', function()
feed(':')
- screen:expect([[
+ screen:expect{grid=[[
|
{0:~ }|
{0:~ }|
:^ |
- ]],nil,nil,function ()
- eq("cmdline_normal", screen.mode)
- end)
+ ]], mode="cmdline_normal"}
feed('x<left>')
- screen:expect([[
+ screen:expect{grid=[[
|
{0:~ }|
{0:~ }|
:^x |
- ]],nil,nil,function ()
- eq("cmdline_insert", screen.mode)
- end)
+ ]], mode="cmdline_insert"}
feed('<insert>')
- screen:expect([[
+ screen:expect{grid=[[
|
{0:~ }|
{0:~ }|
:^x |
- ]],nil,nil,function ()
- eq("cmdline_replace", screen.mode)
- end)
+ ]], mode="cmdline_replace"}
feed('<right>')
- screen:expect([[
+ screen:expect{grid=[[
|
{0:~ }|
{0:~ }|
:x^ |
- ]],nil,nil,function ()
- eq("cmdline_normal", screen.mode)
- end)
+ ]], mode="cmdline_normal"}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
end)
- it('works in visal mode', function()
+ it('works in visual mode', function()
insert("text")
feed('v')
- screen:expect([[
+ screen:expect{grid=[[
tex^t |
{0:~ }|
{0:~ }|
{2:-- VISUAL --} |
- ]],nil,nil,function ()
- eq("visual", screen.mode)
- end)
+ ]], mode="visual"}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
tex^t |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
command('set selection=exclusive')
feed('v')
- screen:expect([[
+ screen:expect{grid=[[
tex^t |
{0:~ }|
{0:~ }|
{2:-- VISUAL --} |
- ]],nil,nil,function ()
- eq("visual_select", screen.mode)
- end)
+ ]], mode="visual_select"}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
tex^t |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
end)
end)
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index debd324977..c531f838c1 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -168,13 +168,13 @@ describe('ui/mouse/input', function()
|
]])
feed('<LeftMouse><11,0>')
- screen:expect([[
+ screen:expect{grid=[[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><6,0>')
screen:expect([[
{sel: + bar }{tab: + foo }{fill: }{tab:X}|
@@ -236,13 +236,13 @@ describe('ui/mouse/input', function()
|
]])
feed('<LeftDrag><4,1>')
- screen:expect([[
+ screen:expect{grid=[[
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
this is fo^o |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><14,1>')
screen:expect([[
{tab: + bar }{sel: + foo }{fill: }{tab:X}|
@@ -254,13 +254,6 @@ describe('ui/mouse/input', function()
end)
it('out of tabline to the left moves tab left', function()
- if helpers.skip_fragile(pending,
- os.getenv("TRAVIS") and (helpers.os_name() == "osx"
- or os.getenv("CLANG_SANITIZER") == "ASAN_UBSAN")) -- #4874
- then
- return
- end
-
feed_command('%delete')
insert('this is foo')
feed_command('silent file foo | tabnew | file bar')
@@ -273,21 +266,21 @@ describe('ui/mouse/input', function()
|
]])
feed('<LeftMouse><11,0>')
- screen:expect([[
+ screen:expect{grid=[[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><11,1>')
- screen:expect([[
+ screen:expect{grid=[[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><6,1>')
screen:expect([[
{sel: + bar }{tab: + foo }{fill: }{tab:X}|
@@ -319,13 +312,13 @@ describe('ui/mouse/input', function()
|
]])
feed('<LeftDrag><4,1>')
- screen:expect([[
+ screen:expect{grid=[[
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
this is fo^o |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><7,1>')
screen:expect([[
{tab: + bar }{sel: + foo }{fill: }{tab:X}|
@@ -537,7 +530,7 @@ describe('ui/mouse/input', function()
mouse |
support and selectio^n |
{0:~ }|
- |
+ :tabprevious |
]])
feed('<LeftMouse><10,0><LeftRelease>') -- go to second tab
helpers.wait()
@@ -547,7 +540,7 @@ describe('ui/mouse/input', function()
^this is bar |
{0:~ }|
{0:~ }|
- |
+ :tabprevious |
]])
feed('<LeftDrag><4,1>')
screen:expect([[
diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua
index 62b08c0967..32e8faf7d3 100644
--- a/test/functional/ui/options_spec.lua
+++ b/test/functional/ui/options_spec.lua
@@ -1,79 +1,85 @@
+local global_helpers = require('test.helpers')
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local shallowcopy = global_helpers.shallowcopy
describe('ui receives option updates', function()
local screen
- before_each(function()
- clear()
+ local function reset(opts, ...)
+ local defaults = {
+ ambiwidth='single',
+ arabicshape=true,
+ emoji=true,
+ guifont='',
+ guifontset='',
+ guifontwide='',
+ linespace=0,
+ showtabline=1,
+ termguicolors=false,
+ ext_cmdline=false,
+ ext_popupmenu=false,
+ ext_tabline=false,
+ ext_wildmenu=false,
+ ext_linegrid=false,
+ ext_hlstate=false,
+ }
+
+ clear(...)
screen = Screen.new(20,5)
- end)
+ screen:attach(opts)
+ -- NB: UI test suite can be run in both "linegrid" and legacy grid mode.
+ -- In both cases check that the received value is the one requested.
+ defaults.ext_linegrid = screen._options.ext_linegrid or false
+ return defaults
+ end
after_each(function()
screen:detach()
end)
- local defaults = {
- ambiwidth='single',
- arabicshape=true,
- emoji=true,
- guifont='',
- guifontset='',
- guifontwide='',
- linespace=0,
- showtabline=1,
- termguicolors=false,
- ext_cmdline=false,
- ext_popupmenu=false,
- ext_tabline=false,
- ext_wildmenu=false,
- }
-
it("for defaults", function()
- screen:attach()
+ local expected = reset()
screen:expect(function()
- eq(defaults, screen.options)
+ eq(expected, screen.options)
end)
end)
it("when setting options", function()
- screen:attach()
- local changed = {}
- for k,v in pairs(defaults) do
- changed[k] = v
- end
+ local expected = reset()
+ local defaults = shallowcopy(expected)
command("set termguicolors")
- changed.termguicolors = true
+ expected.termguicolors = true
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set guifont=Comic\\ Sans")
- changed.guifont = "Comic Sans"
+ expected.guifont = "Comic Sans"
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set showtabline=0")
- changed.showtabline = 0
+ expected.showtabline = 0
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set linespace=13")
- changed.linespace = 13
+ expected.linespace = 13
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set linespace=-11")
- changed.linespace = -11
+ expected.linespace = -11
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set all&")
@@ -83,28 +89,35 @@ describe('ui receives option updates', function()
end)
it('with UI extensions', function()
- local changed = {}
- for k,v in pairs(defaults) do
- changed[k] = v
- end
-
- screen:attach({ext_cmdline=true, ext_wildmenu=true})
- changed.ext_cmdline = true
- changed.ext_wildmenu = true
+ local expected = reset({ext_cmdline=true, ext_wildmenu=true})
+
+ expected.ext_cmdline = true
+ expected.ext_wildmenu = true
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
screen:set_option('ext_popupmenu', true)
- changed.ext_popupmenu = true
+ expected.ext_popupmenu = true
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
screen:set_option('ext_wildmenu', false)
- changed.ext_wildmenu = false
+ expected.ext_wildmenu = false
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
end)
+
+ local function startup_test(headless)
+ local expected = reset(nil,{headless=headless,args={'--cmd', 'set guifont=Comic\\ Sans\\ 12'}})
+ expected.guifont = "Comic Sans 12"
+ screen:expect(function()
+ eq(expected, screen.options)
+ end)
+ end
+
+ it('from startup options with --headless', function() startup_test(true) end)
+ it('from startup options with --embed', function() startup_test(false) end)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 93d8965cb1..1850d436ac 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -51,25 +51,20 @@ describe("shell command :!", function()
end)
it("throttles shell-command output greater than ~10KB", function()
- if os.getenv("TRAVIS") and helpers.os_name() == "osx" then
- pending("[Unreliable on Travis macOS.]", function() end)
- return
- end
-
- screen.timeout = 20000 -- Avoid false failure on slow systems.
child_session.feed_data(
- ":!for i in $(seq 2 3000); do echo XXXXXXXXXX $i; done\n")
+ ":!for i in $(seq 2 30000); do echo XXXXXXXXXX $i; done\n")
-- If we observe any line starting with a dot, then throttling occurred.
- screen:expect("\n.", nil, nil, nil, true)
+ -- Avoid false failure on slow systems.
+ screen:expect{any="\n%.", timeout=20000}
-- Final chunk of output should always be displayed, never skipped.
-- (Throttling is non-deterministic, this test is merely a sanity check.)
screen:expect([[
- XXXXXXXXXX 2997 |
- XXXXXXXXXX 2998 |
- XXXXXXXXXX 2999 |
- XXXXXXXXXX 3000 |
+ XXXXXXXXXX 29997 |
+ XXXXXXXXXX 29998 |
+ XXXXXXXXXX 29999 |
+ XXXXXXXXXX 30000 |
|
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
@@ -92,7 +87,7 @@ describe("shell command :!", function()
eq(2, eval('1+1')) -- Still alive?
end)
- it([[handles control codes]], function()
+ it('handles control codes', function()
if iswin() then
pending('missing printf', function() end)
return
@@ -112,14 +107,14 @@ describe("shell command :!", function()
-- Print BELL control code. #4338
screen.bell = false
feed([[:!printf '\007\007\007\007text'<CR>]])
- screen:expect([[
+ screen:expect{grid=[[
~ |
:!printf '\007\007\007\007text' |
text |
Press ENTER or type command to continue^ |
- ]], nil, nil, function()
+ ]], condition=function()
eq(true, screen.bell)
- end)
+ end}
feed([[<CR>]])
-- Print BS control code.
feed([[:echo system('printf ''\010\n''')<CR>]])
@@ -188,7 +183,7 @@ describe("shell command :!", function()
it('handles binary and multibyte data', function()
feed_command('!cat test/functional/fixtures/shell_data.txt')
screen.bell = false
- screen:expect([[
+ screen:expect{grid=[[
|
{1:~ }|
{4: }|
@@ -199,9 +194,9 @@ describe("shell command :!", function()
t {2:<ff>} |
|
{3:Press ENTER or type command to continue}^ |
- ]], nil, nil, function()
+ ]], condition=function()
eq(true, screen.bell)
- end)
+ end}
end)
it('handles multibyte sequences split over buffer boundaries', function()
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
new file mode 100644
index 0000000000..606c7c1e26
--- /dev/null
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -0,0 +1,260 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, feed = helpers.clear, helpers.feed
+local source = helpers.source
+
+describe('ui/ext_popupmenu', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 8)
+ screen:attach({rgb=true, ext_popupmenu=true})
+ screen:set_default_attr_ids({
+ [1] = {bold=true, foreground=Screen.colors.Blue},
+ [2] = {bold = true},
+ [3] = {reverse = true},
+ [4] = {bold = true, reverse = true},
+ [5] = {bold = true, foreground = Screen.colors.SeaGreen}
+ })
+ end)
+
+ it('works', function()
+ source([[
+ function! TestComplete() abort
+ call complete(1, ['foo', 'bar', 'spam'])
+ return ''
+ endfunction
+ ]])
+ local expected = {
+ {'foo', '', '', ''},
+ {'bar', '', '', ''},
+ {'spam', '', '', ''},
+ }
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect{grid=[[
+ |
+ foo^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=0,
+ anchor={1,0},
+ }}
+
+ feed('<c-p>')
+ screen:expect{grid=[[
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=-1,
+ anchor={1,0},
+ }}
+
+ -- down moves the selection in the menu, but does not insert anything
+ feed('<down><down>')
+ screen:expect{grid=[[
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=1,
+ anchor={1,0},
+ }}
+
+ feed('<cr>')
+ screen:expect{grid=[[
+ |
+ bar^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]]}
+ end)
+end)
+
+describe('popup placement', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(32, 20)
+ screen:attach()
+ screen:set_default_attr_ids({
+ -- popup selected item / scrollbar track
+ ['s'] = {background = Screen.colors.WebGray},
+ -- popup non-selected item
+ ['n'] = {background = Screen.colors.LightMagenta},
+ -- popup scrollbar knob
+ ['c'] = {background = Screen.colors.Grey0},
+ [1] = {bold = true, foreground = Screen.colors.Blue},
+ [2] = {bold = true},
+ [3] = {reverse = true},
+ [4] = {bold = true, reverse = true},
+ [5] = {bold = true, foreground = Screen.colors.SeaGreen}
+ })
+ end)
+
+ it('works with preview-window above', function()
+ feed(':ped<CR><c-w>4+')
+ feed('iaa bb cc dd ee ff gg hh ii jj<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa bb cc dd ee ff gg hh ii jj |
+ aa |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] [Preview][+] }|
+ aa bb cc dd ee ff gg hh ii jj |
+ aa^ |
+ {s:aa }{c: }{1: }|
+ {n:bb }{c: }{1: }|
+ {n:cc }{c: }{1: }|
+ {n:dd }{c: }{1: }|
+ {n:ee }{c: }{1: }|
+ {n:ff }{c: }{1: }|
+ {n:gg }{s: }{1: }|
+ {n:hh }{s: }{4: }|
+ {2:-- }{5:match 1 of 10} |
+ ]])
+ end)
+
+ it('works with preview-window below', function()
+ feed(':ped<CR><c-w>4+<c-w>r')
+ feed('iaa bb cc dd ee ff gg hh ii jj<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa bb cc dd ee ff gg hh ii jj |
+ aa^ |
+ {s:aa }{c: }{1: }|
+ {n:bb }{c: }{1: }|
+ {n:cc }{c: }{1: }|
+ {n:dd }{c: }{1: }|
+ {n:ee }{c: }{1: }|
+ {n:ff }{c: }{1: }|
+ {n:gg }{s: }{1: }|
+ {n:hh }{s: }{4: }|
+ aa bb cc dd ee ff gg hh ii jj |
+ aa |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] [Preview][+] }|
+ {2:-- }{5:match 1 of 10} |
+ ]])
+ end)
+
+ it('works with preview-window above and tall and inverted', function()
+ feed(':ped<CR><c-w>8+')
+ feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>')
+ feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>')
+ feed('kk<cr>ll<cr>mm<cr>nn<cr>oo<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa |
+ bb |
+ cc |
+ dd |
+ {s:aa }{c: }{3:ew][+] }|
+ {n:bb }{c: } |
+ {n:cc }{c: } |
+ {n:dd }{c: } |
+ {n:ee }{c: } |
+ {n:ff }{c: } |
+ {n:gg }{c: } |
+ {n:hh }{c: } |
+ {n:ii }{c: } |
+ {n:jj }{c: } |
+ {n:kk }{c: } |
+ {n:ll }{s: } |
+ {n:mm }{s: } |
+ aa^ |
+ {4:[No Name] [+] }|
+ {2:-- }{5:match 1 of 15} |
+ ]])
+ end)
+
+ it('works with preview-window above and short and inverted', function()
+ feed(':ped<CR><c-w>4+')
+ feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>')
+ feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa |
+ bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ {s:aa } |
+ {n:bb }{3:iew][+] }|
+ {n:cc } |
+ {n:dd } |
+ {n:ee } |
+ {n:ff } |
+ {n:gg } |
+ {n:hh } |
+ {n:ii } |
+ {n:jj } |
+ aa^ |
+ {4:[No Name] [+] }|
+ {2:-- }{5:match 1 of 10} |
+ ]])
+ end)
+
+ it('works with preview-window below and inverted', function()
+ feed(':ped<CR><c-w>4+<c-w>r')
+ feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>')
+ feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ {s:aa }{c: } |
+ {n:bb }{c: } |
+ {n:cc }{c: } |
+ {n:dd }{c: } |
+ {n:ee }{c: } |
+ {n:ff }{c: } |
+ {n:gg }{s: } |
+ {n:hh }{s: } |
+ aa^ |
+ {4:[No Name] [+] }|
+ aa |
+ bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ hh |
+ {3:[No Name] [Preview][+] }|
+ {2:-- }{5:match 1 of 10} |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 7607131e9b..af036913d8 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -71,24 +71,35 @@
-- To help write screen tests, see Screen:snapshot_util().
-- To debug screen tests, see Screen:redraw_debug().
+local global_helpers = require('test.helpers')
+local shallowcopy = global_helpers.shallowcopy
local helpers = require('test.functional.helpers')(nil)
local request, run, uimeths = helpers.request, helpers.run, helpers.uimeths
+local eq = helpers.eq
local dedent = helpers.dedent
+local inspect = require('inspect')
+
+local function isempty(v)
+ return type(v) == 'table' and next(v) == nil
+end
+
local Screen = {}
Screen.__index = Screen
local debug_screen
-local default_screen_timeout = 3500
+local default_timeout_factor = 1
if os.getenv('VALGRIND') then
- default_screen_timeout = default_screen_timeout * 3
+ default_timeout_factor = default_timeout_factor * 3
end
if os.getenv('CI') then
- default_screen_timeout = default_screen_timeout * 3
+ default_timeout_factor = default_timeout_factor * 3
end
+local default_screen_timeout = default_timeout_factor * 3500
+
do
local spawn, nvim_prog = helpers.spawn, helpers.nvim_prog
local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', '--embed'})
@@ -138,16 +149,26 @@ function Screen.new(width, height)
suspended = false,
mode = 'normal',
options = {},
+ popupmenu = nil,
+ cmdline = {},
+ cmdline_block = {},
+ wildmenu_items = nil,
+ wildmenu_selected = nil,
_default_attr_ids = nil,
_default_attr_ignore = nil,
_mouse_enabled = true,
_attrs = {},
+ _hl_info = {},
+ _attr_table = {[0]={{},{}}},
+ _clear_attrs = {},
+ _new_attrs = false,
+ _width = width,
+ _height = height,
_cursor = {
row = 1, col = 1
},
_busy = false
}, Screen)
- self:_handle_resize(width, height)
return self
end
@@ -159,11 +180,26 @@ function Screen:set_default_attr_ignore(attr_ignore)
self._default_attr_ignore = attr_ignore
end
+function Screen:set_hlstate_cterm(val)
+ self._hlstate_cterm = val
+end
+
function Screen:attach(options)
if options == nil then
- options = {rgb=true}
+ options = {}
end
+ if options.ext_linegrid == nil then
+ options.ext_linegrid = true
+ end
+ self._options = options
+ self._clear_attrs = (options.ext_linegrid and {{},{}}) or {}
+ self:_handle_resize(self._width, self._height)
uimeths.attach(self._width, self._height, options)
+ if self._options.rgb == nil then
+ -- nvim defaults to rgb=true internally,
+ -- simplify test code by doing the same.
+ self._options.rgb = true
+ end
end
function Screen:detach()
@@ -176,41 +212,123 @@ end
function Screen:set_option(option, value)
uimeths.set_option(option, value)
+ self._options[option] = value
end
--- Asserts that `expected` eventually matches the screen state.
+-- canonical order of ext keys, used to generate asserts
+local ext_keys = {
+ 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos'
+}
+
+-- Asserts that the screen state eventually matches an expected state
+--
+-- This function can either be called with the positional forms
+--
+-- screen:expect(grid, [attr_ids, attr_ignore])
+-- screen:expect(condition)
+--
+-- or to use additional arguments (or grid and condition at the same time)
+-- the keyword form has to be used:
--
--- expected: Expected screen state (string). Each line represents a screen
+-- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end}
+--
+--
+-- grid: Expected screen state (string). Each line represents a screen
-- row. Last character of each row (typically "|") is stripped.
-- Common indentation is stripped.
--- Used as `condition` if NOT a string; must be the ONLY arg then.
-- attr_ids: Expected text attributes. Screen rows are transformed according
-- to this table, as follows: each substring S composed of
-- characters having the same attributes will be substituted by
-- "{K:S}", where K is a key in `attr_ids`. Any unexpected
-- attributes in the final state are an error.
--- attr_ignore: Ignored text attributes, or `true` to ignore all.
--- condition: Function asserting some arbitrary condition.
--- any: true: Succeed if `expected` matches ANY screen line(s).
--- false (default): `expected` must match screen exactly.
-function Screen:expect(expected, attr_ids, attr_ignore, condition, any)
+-- Use screen:set_default_attr_ids() to define attributes for many
+-- expect() calls.
+-- attr_ignore: Ignored text attributes, or `true` to ignore all. By default
+-- nothing is ignored.
+-- condition: Function asserting some arbitrary condition. Return value is
+-- ignored, throw an error (use eq() or similar) to signal failure.
+-- any: Lua pattern string expected to match a screen line. NB: the
+-- following chars are magic characters
+-- ( ) . % + - * ? [ ^ $
+-- and must be escaped with a preceding % for a literal match.
+-- mode: Expected mode as signaled by "mode_change" event
+-- unchanged: Test that the screen state is unchanged since the previous
+-- expect(...). Any flush event resulting in a different state is
+-- considered an error. Not observing any events until timeout
+-- is acceptable.
+-- intermediate:Test that the final state is the same as the previous expect,
+-- but expect an intermediate state that is different. If possible
+-- it is better to use an explicit screen:expect(...) for this
+-- intermediate state.
+-- reset: Reset the state internal to the test Screen before starting to
+-- receive updates. This should be used after command("redraw!")
+-- or some other mechanism that will invoke "redraw!", to check
+-- that all screen state is transmitted again. This includes
+-- state related to ext_ features as mentioned below.
+-- timeout: maximum time that will be waited until the expected state is
+-- seen (or maximum time to observe an incorrect change when
+-- `unchanged` flag is used)
+--
+-- The following keys should be used to expect the state of various ext_
+-- features. Note that an absent key will assert that the item is currently
+-- NOT present on the screen, also when positional form is used.
+--
+-- popupmenu: Expected ext_popupmenu state,
+-- cmdline: Expected ext_cmdline state, as an array of cmdlines of
+-- different level.
+-- cmdline_block: Expected ext_cmdline block (for function definitions)
+-- wildmenu_items: Expected items for ext_wildmenu
+-- wildmenu_pos: Expected position for ext_wildmenu
+function Screen:expect(expected, attr_ids, attr_ignore)
+ local grid, condition = nil, nil
local expected_rows = {}
- if type(expected) ~= "string" then
- assert(not (attr_ids or attr_ignore or condition or any))
+ if type(expected) == "table" then
+ assert(not (attr_ids ~= nil or attr_ignore ~= nil))
+ local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
+ any=true, mode=true, unchanged=true, intermediate=true,
+ reset=true, timeout=true}
+ for _, v in ipairs(ext_keys) do
+ is_key[v] = true
+ end
+ for k, _ in pairs(expected) do
+ if not is_key[k] then
+ error("Screen:expect: Unknown keyword argument '"..k.."'")
+ end
+ end
+ grid = expected.grid
+ attr_ids = expected.attr_ids
+ attr_ignore = expected.attr_ignore
+ condition = expected.condition
+ assert(not (expected.any ~= nil and grid ~= nil))
+ elseif type(expected) == "string" then
+ grid = expected
+ expected = {}
+ elseif type(expected) == "function" then
+ assert(not (attr_ids ~= nil or attr_ignore ~= nil))
condition = expected
- expected = nil
+ expected = {}
else
+ assert(false)
+ end
+
+ if grid ~= nil then
-- Remove the last line and dedent. Note that gsub returns more then one
-- value.
- expected = dedent(expected:gsub('\n[ ]+$', ''), 0)
- for row in expected:gmatch('[^\n]+') do
+ grid = dedent(grid:gsub('\n[ ]+$', ''), 0)
+ for row in grid:gmatch('[^\n]+') do
row = row:sub(1, #row - 1) -- Last char must be the screen delimiter.
table.insert(expected_rows, row)
end
end
- local ids = attr_ids or self._default_attr_ids
- local ignore = attr_ignore or self._default_attr_ignore
- self:wait(function()
+ local attr_state = {
+ ids = attr_ids or self._default_attr_ids,
+ ignore = attr_ignore or self._default_attr_ignore,
+ }
+ if self._options.ext_hlstate then
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
+ end
+ self._new_attrs = false
+ self:_wait(function()
if condition ~= nil then
local status, res = pcall(condition)
if not status then
@@ -218,28 +336,32 @@ function Screen:expect(expected, attr_ids, attr_ignore, condition, any)
end
end
- if expected and not any and self._height ~= #expected_rows then
+ if grid ~= nil and self._height ~= #expected_rows then
return ("Expected screen state's row count(" .. #expected_rows
.. ') differs from configured height(' .. self._height .. ') of Screen.')
end
+ if self._options.ext_hlstate and self._new_attrs then
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
+ end
+
local actual_rows = {}
for i = 1, self._height do
- actual_rows[i] = self:_row_repr(self._rows[i], ids, ignore)
+ actual_rows[i] = self:_row_repr(self._rows[i], attr_state)
end
- if expected == nil then
- return
- elseif any then
- -- Search for `expected` anywhere in the screen lines.
+ if expected.any ~= nil then
+ -- Search for `any` anywhere in the screen lines.
local actual_screen_str = table.concat(actual_rows, '\n')
- if nil == string.find(actual_screen_str, expected) then
+ if nil == string.find(actual_screen_str, expected.any) then
return (
'Failed to match any screen lines.\n'
- .. 'Expected (anywhere): "' .. expected .. '"\n'
+ .. 'Expected (anywhere): "' .. expected.any .. '"\n'
.. 'Actual:\n |' .. table.concat(actual_rows, '|\n |') .. '|\n\n')
end
- else
+ end
+
+ if grid ~= nil then
-- `expected` must match the screen lines exactly.
for i = 1, self._height do
if expected_rows[i] ~= actual_rows[i] then
@@ -259,21 +381,87 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
end
end
- end)
+
+ -- Extension features. The default expectations should cover the case of
+ -- the ext_ feature being disabled, or the feature currently not activated
+ -- (for instance no external cmdline visible). Some extensions require
+ -- preprocessing to represent highlights in a reproducible way.
+ local extstate = self:_extstate_repr(attr_state)
+
+ -- convert assertion errors into invalid screen state descriptions
+ local status, res = pcall(function()
+ for _, k in ipairs(ext_keys) do
+ -- Empty states is considered the default and need not be mentioned
+ if not (expected[k] == nil and isempty(extstate[k])) then
+ eq(expected[k], extstate[k], k)
+ end
+ end
+ if expected.mode ~= nil then
+ eq(expected.mode, self.mode, "mode")
+ end
+ end)
+ if not status then
+ return tostring(res)
+ end
+ end, expected)
end
-function Screen:wait(check, timeout)
- local err, checked = false
+function Screen:_wait(check, flags)
+ local err, checked = false, false
local success_seen = false
local failure_after_success = false
+ local did_flush = true
+ local warn_immediate = not (flags.unchanged or flags.intermediate)
+
+ if flags.intermediate and flags.unchanged then
+ error("Choose only one of 'intermediate' and 'unchanged', not both")
+ end
+
+ if flags.reset then
+ -- throw away all state, we expect it to be retransmitted
+ self:_reset()
+ end
+
+ -- Maximum timeout, after which a incorrect state will be regarded as a
+ -- failure
+ local timeout = flags.timeout or self.timeout
+
+ -- Minimal timeout before the loop is allowed to be stopped so we
+ -- always do some check for failure after success.
+ local minimal_timeout = default_timeout_factor * 2
+
+ local immediate_seen, intermediate_seen = false, false
+ if not check() then
+ minimal_timeout = default_timeout_factor * 20
+ immediate_seen = true
+ end
+
+ -- for an unchanged test, flags.timeout means the time during the state is
+ -- expected to be unchanged, so always wait this full time.
+ if (flags.unchanged or flags.intermediate) and flags.timeout ~= nil then
+ minimal_timeout = timeout
+ end
+
+ assert(timeout >= minimal_timeout)
+ local did_miminal_timeout = false
+
local function notification_cb(method, args)
assert(method == 'redraw')
- self:_redraw(args)
+ did_flush = self:_redraw(args)
+ if not did_flush then
+ return
+ end
err = check()
checked = true
+ if err and immediate_seen then
+ intermediate_seen = true
+ end
+
if not err then
success_seen = true
- helpers.stop()
+ if did_miminal_timeout then
+ helpers.stop()
+ end
elseif success_seen and #args > 0 then
failure_after_success = true
--print(require('inspect')(args))
@@ -281,37 +469,88 @@ function Screen:wait(check, timeout)
return true
end
- run(nil, notification_cb, nil, timeout or self.timeout)
- if not checked then
+ run(nil, notification_cb, nil, minimal_timeout)
+ if not did_flush then
+ err = "no flush received"
+ elseif not checked then
err = check()
+ if not err and flags.unchanged then
+ -- expecting NO screen change: use a shorter timout
+ success_seen = true
+ end
+ end
+
+ if not success_seen then
+ did_miminal_timeout = true
+ run(nil, notification_cb, nil, timeout-minimal_timeout)
+ end
+
+ local did_warn = false
+ if warn_immediate and immediate_seen then
+ print([[
+
+Warning: A screen test has immediate success. Try to avoid this unless the
+purpose of the test really requires it.]])
+ if intermediate_seen then
+ print([[
+There are intermediate states between the two identical expects.
+Use screen:snapshot_util() or screen:redraw_debug() to find them, and add them
+to the test if they make sense.
+]])
+ else
+ print([[If necessary, silence this warning by
+supplying the 'unchanged' argument to screen:expect.]])
+ end
+ did_warn = true
end
if failure_after_success then
print([[
Warning: Screen changes were received after the expected state. This indicates
-indeterminism in the test. Try adding wait() (or screen:expect(...)) between
+indeterminism in the test. Try adding screen:expect(...) (or wait()) between
asynchronous (feed(), nvim_input()) and synchronous API calls.
- - Use Screen:redraw_debug() to investigate the problem.
+ - Use Screen:redraw_debug() to investigate the problem. It might find
+ relevant intermediate states that should be added to the test to make it
+ more robust.
+ - If the point of the test is to assert the state after some user input
+ sent with feed(...), also adding an screen:expect(...) before the feed(...)
+ will help ensure the input is sent to nvim when nvim is in a predictable
+ state. This is preferable to using wait(), as it is more closely emulates
+ real user interaction.
- wait() can trigger redraws and consequently generate more indeterminism.
In that case try removing every wait().
]])
+ did_warn = true
+ end
+
+
+ if err then
+ assert(false, err)
+ elseif did_warn then
local tb = debug.traceback()
local index = string.find(tb, '\n%s*%[C]')
print(string.sub(tb,1,index))
end
- if err then
- assert(false, err)
+ if flags.intermediate then
+ assert(intermediate_seen, "expected intermediate screen state before final screen state")
+ elseif flags.unchanged then
+ assert(not intermediate_seen, "expected screen state to be unchanged")
end
end
function Screen:sleep(ms)
- pcall(function() self:wait(function() return "error" end, ms) end)
+ local function notification_cb(method, args)
+ assert(method == 'redraw')
+ self:_redraw(args)
+ end
+ run(nil, notification_cb, nil, ms)
end
function Screen:_redraw(updates)
- for _, update in ipairs(updates) do
+ local did_flush = false
+ for k, update in ipairs(updates) do
-- print('--')
-- print(require('inspect')(update))
local method = update[1]
@@ -326,8 +565,11 @@ function Screen:_redraw(updates)
self._on_event(method, update[i])
end
end
- -- print(self:_current_screen())
+ if k == #updates and method == "flush" then
+ did_flush = true
+ end
end
+ return did_flush
end
function Screen:set_on_event_handler(callback)
@@ -339,7 +581,7 @@ function Screen:_handle_resize(width, height)
for _ = 1, height do
local cols = {}
for _ = 1, width do
- table.insert(cols, {text = ' ', attrs = {}})
+ table.insert(cols, {text = ' ', attrs = self._clear_attrs, hl_id = 0})
end
table.insert(rows, cols)
end
@@ -353,14 +595,59 @@ function Screen:_handle_resize(width, height)
}
end
+function Screen:_handle_flush()
+end
+
+function Screen:_handle_grid_resize(grid, width, height)
+ assert(grid == 1)
+ self:_handle_resize(width, height)
+end
+
+function Screen:_reset()
+ -- TODO: generalize to multigrid later
+ self:_handle_grid_clear(1)
+
+ -- TODO: share with initialization, so it generalizes?
+ self.popupmenu = nil
+ self.cmdline = {}
+ self.cmdline_block = {}
+ self.wildmenu_items = nil
+ self.wildmenu_pos = nil
+end
+
+
function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
self._cursor_style_enabled = cursor_style_enabled
+ for _, item in pairs(mode_info) do
+ -- attr IDs are not stable, but their value should be
+ if item.attr_id ~= nil then
+ item.attr = self._attr_table[item.attr_id][1]
+ item.attr_id = nil
+ end
+ if item.attr_id_lm ~= nil then
+ item.attr_lm = self._attr_table[item.attr_id_lm][1]
+ item.attr_id_lm = nil
+ end
+ end
self._mode_info = mode_info
end
function Screen:_handle_clear()
- self:_clear_block(self._scroll_region.top, self._scroll_region.bot,
- self._scroll_region.left, self._scroll_region.right)
+ -- the first implemented UI protocol clients (python-gui and builitin TUI)
+ -- allowed the cleared region to be restricted by setting the scroll region.
+ -- this was never used by nvim tough, and not documented and implemented by
+ -- newer clients, to check we remain compatible with both kind of clients,
+ -- ensure the scroll region is in a reset state.
+ local expected_region = {
+ top = 1, bot = self._height, left = 1, right = self._width
+ }
+ eq(expected_region, self._scroll_region)
+ self:_clear_block(1, self._height, 1, self._width)
+end
+
+function Screen:_handle_grid_clear(grid)
+ assert(grid == 1)
+ self:_clear_block(1, self._height, 1, self._width)
end
function Screen:_handle_eol_clear()
@@ -373,6 +660,12 @@ function Screen:_handle_cursor_goto(row, col)
self._cursor.col = col + 1
end
+function Screen:_handle_grid_cursor_goto(grid, row, col)
+ assert(grid == 1)
+ self._cursor.row = row + 1
+ self._cursor.col = col + 1
+end
+
function Screen:_handle_busy_start()
self._busy = true
end
@@ -406,45 +699,85 @@ function Screen:_handle_scroll(count)
local bot = self._scroll_region.bot
local left = self._scroll_region.left
local right = self._scroll_region.right
+ self:_handle_grid_scroll(1, top-1, bot, left-1, right, count, 0)
+end
+
+function Screen:_handle_grid_scroll(grid, top, bot, left, right, rows, cols)
+ top = top+1
+ left = left+1
+ assert(grid == 1)
+ assert(cols == 0)
local start, stop, step
- if count > 0 then
+ if rows > 0 then
start = top
- stop = bot - count
+ stop = bot - rows
step = 1
else
start = bot
- stop = top - count
+ stop = top - rows
step = -1
end
-- shift scroll region
for i = start, stop, step do
local target = self._rows[i]
- local source = self._rows[i + count]
+ local source = self._rows[i + rows]
for j = left, right do
target[j].text = source[j].text
target[j].attrs = source[j].attrs
+ target[j].hl_id = source[j].hl_id
end
end
-- clear invalid rows
- for i = stop + step, stop + count, step do
+ for i = stop + step, stop + rows, step do
self:_clear_row_section(i, left, right)
end
end
+function Screen:_handle_hl_attr_define(id, rgb_attrs, cterm_attrs, info)
+ self._attr_table[id] = {rgb_attrs, cterm_attrs}
+ self._hl_info[id] = info
+ self._new_attrs = true
+end
+
function Screen:_handle_highlight_set(attrs)
self._attrs = attrs
end
function Screen:_handle_put(str)
+ assert(not self._options.ext_linegrid)
local cell = self._rows[self._cursor.row][self._cursor.col]
cell.text = str
cell.attrs = self._attrs
+ cell.hl_id = -1
self._cursor.col = self._cursor.col + 1
end
+function Screen:_handle_grid_line(grid, row, col, items)
+ assert(self._options.ext_linegrid)
+ assert(grid == 1)
+ local line = self._rows[row+1]
+ local colpos = col+1
+ local hl = self._clear_attrs
+ local hl_id = 0
+ 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
+ hl = self._attr_table[hl_id]
+ end
+ for _ = 1, (count or 1) do
+ local cell = line[colpos]
+ cell.text = text
+ cell.hl_id = hl_id
+ cell.attrs = hl
+ colpos = colpos+1
+ end
+ end
+end
+
function Screen:_handle_bell()
self.bell = true
end
@@ -453,7 +786,14 @@ function Screen:_handle_visual_bell()
self.visual_bell = true
end
-function Screen:_handle_default_colors_set()
+function Screen:_handle_default_colors_set(rgb_fg, rgb_bg, rgb_sp, cterm_fg, cterm_bg)
+ self.default_colors = {
+ rgb_fg=rgb_fg,
+ rgb_bg=rgb_bg,
+ rgb_sp=rgb_sp,
+ cterm_fg=cterm_fg,
+ cterm_bg=cterm_bg
+ }
end
function Screen:_handle_update_fg(fg)
@@ -488,6 +828,63 @@ function Screen:_handle_option_set(name, value)
self.options[name] = value
end
+function Screen:_handle_popupmenu_show(items, selected, row, col)
+ self.popupmenu = {items=items,pos=selected, anchor={row, col}}
+end
+
+function Screen:_handle_popupmenu_select(selected)
+ self.popupmenu.pos = selected
+end
+
+function Screen:_handle_popupmenu_hide()
+ self.popupmenu = nil
+end
+
+function Screen:_handle_cmdline_show(content, pos, firstc, prompt, indent, level)
+ if firstc == '' then firstc = nil end
+ if prompt == '' then prompt = nil end
+ if indent == 0 then indent = nil end
+ self.cmdline[level] = {content=content, pos=pos, firstc=firstc,
+ prompt=prompt, indent=indent}
+end
+
+function Screen:_handle_cmdline_hide(level)
+ self.cmdline[level] = nil
+end
+
+function Screen:_handle_cmdline_special_char(char, shift, level)
+ -- cleared by next cmdline_show on the same level
+ self.cmdline[level].special = {char, shift}
+end
+
+function Screen:_handle_cmdline_pos(pos, level)
+ self.cmdline[level].pos = pos
+end
+
+function Screen:_handle_cmdline_block_show(block)
+ self.cmdline_block = block
+end
+
+function Screen:_handle_cmdline_block_append(item)
+ self.cmdline_block[#self.cmdline_block+1] = item
+end
+
+function Screen:_handle_cmdline_block_hide()
+ self.cmdline_block = {}
+end
+
+function Screen:_handle_wildmenu_show(items)
+ self.wildmenu_items = items
+end
+
+function Screen:_handle_wildmenu_select(pos)
+ self.wildmenu_pos = pos
+end
+
+function Screen:_handle_wildmenu_hide()
+ self.wildmenu_items, self.wildmenu_pos = nil, nil
+end
+
function Screen:_clear_block(top, bot, left, right)
for i = top, bot do
self:_clear_row_section(i, left, right)
@@ -498,15 +895,19 @@ function Screen:_clear_row_section(rownum, startcol, stopcol)
local row = self._rows[rownum]
for i = startcol, stopcol do
row[i].text = ' '
- row[i].attrs = {}
+ row[i].attrs = self._clear_attrs
end
end
-function Screen:_row_repr(row, attr_ids, attr_ignore)
+function Screen:_row_repr(row, attr_state)
local rv = {}
local current_attr_id
for i = 1, self._width do
- local attr_id = self:_get_attr_id(attr_ids, attr_ignore, row[i].attrs)
+ local attrs = row[i].attrs
+ if self._options.ext_linegrid then
+ attrs = attrs[(self._options.rgb and 1) or 2]
+ end
+ local attr_id = self:_get_attr_id(attr_state, attrs, row[i].hl_id)
if current_attr_id and attr_id ~= current_attr_id then
-- close current attribute bracket, add it before any whitespace
-- up to the current cell
@@ -532,14 +933,42 @@ function Screen:_row_repr(row, attr_ids, attr_ignore)
return table.concat(rv, '')--:gsub('%s+$', '')
end
+function Screen:_extstate_repr(attr_state)
+ local cmdline = {}
+ for i, entry in pairs(self.cmdline) do
+ entry = shallowcopy(entry)
+ entry.content = self:_chunks_repr(entry.content, attr_state)
+ cmdline[i] = entry
+ end
+
+ local cmdline_block = {}
+ for i, entry in ipairs(self.cmdline_block) do
+ cmdline_block[i] = self:_chunks_repr(entry, attr_state)
+ end
-function Screen:_current_screen()
- -- get a string that represents the current screen state(debugging helper)
- local rv = {}
- for i = 1, self._height do
- table.insert(rv, "'"..self:_row_repr(self._rows[i]).."'")
+ return {
+ popupmenu=self.popupmenu,
+ cmdline=cmdline,
+ cmdline_block=cmdline_block,
+ wildmenu_items=self.wildmenu_items,
+ wildmenu_pos=self.wildmenu_pos,
+ }
+end
+
+function Screen:_chunks_repr(chunks, attr_state)
+ local repr_chunks = {}
+ for i, chunk in ipairs(chunks) do
+ local hl, text = unpack(chunk)
+ local attrs
+ if self._options.ext_linegrid then
+ attrs = self._attr_table[hl][1]
+ else
+ attrs = hl
+ end
+ local attr_id = self:_get_attr_id(attr_state, attrs, hl)
+ repr_chunks[i] = {text, attr_id}
end
- return table.concat(rv, '\n')
+ return repr_chunks
end
-- Generates tests. Call it where Screen:expect() would be. Waits briefly, then
@@ -570,56 +999,179 @@ function Screen:redraw_debug(attrs, ignore, timeout)
end
function Screen:print_snapshot(attrs, ignore)
+ attrs = attrs or self._default_attr_ids
if ignore == nil then
ignore = self._default_attr_ignore
end
- if attrs == nil then
- attrs = {}
- if self._default_attr_ids ~= nil then
- for i, a in pairs(self._default_attr_ids) do
- attrs[i] = a
+ local attr_state = {
+ ids = {},
+ ignore = ignore,
+ mutable = true, -- allow _row_repr to add missing highlights
+ }
+
+ if attrs ~= nil then
+ for i, a in pairs(attrs) do
+ attr_state.ids[i] = a
+ end
+ end
+ if self._options.ext_hlstate then
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids)
+ end
+
+ local lines = {}
+ for i = 1, self._height do
+ table.insert(lines, " "..self:_row_repr(self._rows[i], attr_state).."|")
+ end
+
+ local ext_state = self:_extstate_repr(attr_state)
+ local keys = false
+ for k, v in pairs(ext_state) do
+ if isempty(v) then
+ ext_state[k] = nil -- deleting keys while iterating is ok
+ else
+ keys = true
+ end
+ end
+
+ local attrstr = ""
+ if attr_state.modified then
+ local attrstrs = {}
+ for i, a in pairs(attr_state.ids) do
+ local dict
+ if self._options.ext_hlstate then
+ dict = self:_pprint_hlstate(a)
+ else
+ dict = "{"..self:_pprint_attrs(a).."}"
end
+ local keyval = (type(i) == "number") and "["..tostring(i).."]" or i
+ table.insert(attrstrs, " "..keyval.." = "..dict..",")
end
+ attrstr = (", "..(keys and "attr_ids=" or "")
+ .."{\n"..table.concat(attrstrs, "\n").."\n}")
+ end
+ print( "\nscreen:expect"..(keys and "{grid=" or "(").."[[")
+ print( table.concat(lines, '\n'))
+ io.stdout:write( "]]"..attrstr)
+ for _, k in ipairs(ext_keys) do
+ if ext_state[k] ~= nil then
+ io.stdout:write(", "..k.."="..inspect(ext_state[k]))
+ end
+ end
+ print((keys and "}" or ")").."\n")
+ io.stdout:flush()
+end
- if ignore ~= true then
- for i = 1, self._height do
- local row = self._rows[i]
- for j = 1, self._width do
- local attr = row[j].attrs
- if self:_attr_index(attrs, attr) == nil and self:_attr_index(ignore, attr) == nil then
- if not self:_equal_attrs(attr, {}) then
- table.insert(attrs, attr)
+function Screen:_insert_hl_id(attr_state, hl_id)
+ if attr_state.id_to_index[hl_id] ~= nil then
+ return attr_state.id_to_index[hl_id]
+ end
+ local raw_info = self._hl_info[hl_id]
+ local info = {}
+ if #raw_info > 1 then
+ for i, item in ipairs(raw_info) do
+ info[i] = self:_insert_hl_id(attr_state, item.id)
+ end
+ else
+ info[1] = {}
+ for k, v in pairs(raw_info[1]) do
+ if k ~= "id" then
+ info[1][k] = v
+ end
+ end
+ end
+
+ local entry = self._attr_table[hl_id]
+ local attrval
+ if self._hlstate_cterm then
+ attrval = {entry[1], entry[2], info} -- unpack() doesn't work
+ else
+ attrval = {entry[1], info}
+ end
+
+
+ table.insert(attr_state.ids, attrval)
+ attr_state.id_to_index[hl_id] = #attr_state.ids
+ return #attr_state.ids
+end
+
+function Screen:hlstate_check_attrs(attrs)
+ local id_to_index = {}
+ for i = 1,#self._attr_table do
+ local iinfo = self._hl_info[i]
+ local matchinfo = {}
+ if #iinfo > 1 then
+ for k,item in ipairs(iinfo) do
+ matchinfo[k] = id_to_index[item.id]
+ end
+ else
+ matchinfo = iinfo
+ end
+ for k,v in pairs(attrs) do
+ local attr, info, attr_rgb, attr_cterm
+ if self._hlstate_cterm then
+ attr_rgb, attr_cterm, info = unpack(v)
+ attr = {attr_rgb, attr_cterm}
+ else
+ attr, info = unpack(v)
+ end
+ if self:_equal_attr_def(attr, self._attr_table[i]) then
+ if #info == #matchinfo then
+ local match = false
+ if #info == 1 then
+ if self:_equal_info(info[1],matchinfo[1]) then
+ match = true
+ end
+ else
+ match = true
+ for j = 1,#info do
+ if info[j] ~= matchinfo[j] then
+ match = false
+ end
end
end
+ if match then
+ id_to_index[i] = k
+ end
end
end
end
end
+ return id_to_index
+end
- local rv = {}
- for i = 1, self._height do
- table.insert(rv, " "..self:_row_repr(self._rows[i],attrs, ignore).."|")
- end
- local attrstrs = {}
- local alldefault = true
- for i, a in ipairs(attrs) do
- if self._default_attr_ids == nil or self._default_attr_ids[i] ~= a then
- alldefault = false
- end
- local dict = "{"..self:_pprint_attrs(a).."}"
- table.insert(attrstrs, "["..tostring(i).."] = "..dict)
- end
- local attrstr = "{"..table.concat(attrstrs, ", ").."}"
- print( "\nscreen:expect([[")
- print( table.concat(rv, '\n'))
- if alldefault then
- print( "]])\n")
+
+function Screen:_pprint_hlstate(item)
+ --print(require('inspect')(item))
+ local attrdict = "{"..self:_pprint_attrs(item[1]).."}, "
+ local attrdict2, hlinfo
+ if self._hlstate_cterm then
+ attrdict2 = "{"..self:_pprint_attrs(item[2]).."}, "
+ hlinfo = item[3]
+ else
+ attrdict2 = ""
+ hlinfo = item[2]
+ end
+ local descdict = "{"..self:_pprint_hlinfo(hlinfo).."}"
+ return "{"..attrdict..attrdict2..descdict.."}"
+end
+
+function Screen:_pprint_hlinfo(states)
+ if #states == 1 then
+ local items = {}
+ for f, v in pairs(states[1]) do
+ local desc = tostring(v)
+ if type(v) == type("") then
+ desc = '"'..desc..'"'
+ end
+ table.insert(items, f.." = "..desc)
+ end
+ return "{"..table.concat(items, ", ").."}"
else
- print( "]], "..attrstr..")\n")
+ return table.concat(states, ", ")
end
- io.stdout:flush()
end
+
function Screen:_pprint_attrs(attrs)
local items = {}
for f, v in pairs(attrs) do
@@ -643,32 +1195,64 @@ local function backward_find_meaningful(tbl, from) -- luacheck: no unused
return from
end
-function Screen:_get_attr_id(attr_ids, ignore, attrs)
- if not attr_ids then
+function Screen:_get_attr_id(attr_state, attrs, hl_id)
+ if not attr_state.ids then
return
end
- for id, a in pairs(attr_ids) do
- if self:_equal_attrs(a, attrs) then
- return id
- end
+
+ if self._options.ext_hlstate then
+ local id = attr_state.id_to_index[hl_id]
+ if id ~= nil or hl_id == 0 then
+ return id
+ end
+ if attr_state.mutable then
+ id = self:_insert_hl_id(attr_state, hl_id)
+ attr_state.modified = true
+ return id
+ end
+ return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
+ else
+ for id, a in pairs(attr_state.ids) do
+ if self:_equal_attrs(a, attrs) then
+ return id
+ end
+ end
+ if self:_equal_attrs(attrs, {}) or
+ attr_state.ignore == true or
+ self:_attr_index(attr_state.ignore, attrs) ~= nil then
+ -- ignore this attrs
+ return nil
+ end
+ if attr_state.mutable then
+ table.insert(attr_state.ids, attrs)
+ attr_state.modified = true
+ return #attr_state.ids
+ end
+ return "UNEXPECTED "..self:_pprint_attrs(attrs)
end
- if self:_equal_attrs(attrs, {}) or
- ignore == true or self:_attr_index(ignore, attrs) ~= nil then
- -- ignore this attrs
- return nil
+end
+
+function Screen:_equal_attr_def(a, b)
+ if self._hlstate_cterm then
+ return self:_equal_attrs(a[1],b[1]) and self:_equal_attrs(a[2],b[2])
+ else
+ return self:_equal_attrs(a,b[1])
end
- return "UNEXPECTED "..self:_pprint_attrs(attrs)
end
function Screen:_equal_attrs(a, b)
return a.bold == b.bold and a.standout == b.standout and
a.underline == b.underline and a.undercurl == b.undercurl and
a.italic == b.italic and a.reverse == b.reverse and
- a.foreground == b.foreground and
- a.background == b.background and
+ a.foreground == b.foreground and a.background == b.background and
a.special == b.special
end
+function Screen:_equal_info(a, b)
+ return a.kind == b.kind and a.hi_name == b.hi_name and
+ a.ui_name == b.ui_name
+end
+
function Screen:_attr_index(attrs, attr)
if not attrs then
return nil
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 6f04cde4d4..1a8b7d543a 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -48,13 +48,13 @@ describe('screen', function()
end)
end)
-describe('Screen', function()
+local function screen_tests(linegrid)
local screen
before_each(function()
clear()
screen = Screen.new()
- screen:attach()
+ screen:attach({rgb=true,ext_linegrid=linegrid})
screen:set_default_attr_ids( {
[0] = {bold=true, foreground=255},
[1] = {bold=true, reverse=true},
@@ -354,6 +354,140 @@ describe('Screen', function()
{0:~ }|
|
]])
+
+ feed(':echo "'..string.rep('x\\n', 12)..'"<cr>')
+ screen:expect([[
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ |
+ {7:Press ENTER or type command to continue}^ |
+ ]])
+
+ feed('<cr>')
+ screen:expect([[
+ {4: [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ end)
+
+ it('redraws properly with :tab split right after scroll', function()
+ feed('15Ofoo<esc>15Obar<esc>gg')
+
+ command('vsplit')
+ screen:expect([[
+ ^foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ {1:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+
+ feed('<PageDown>')
+ screen:expect([[
+ ^foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ {1:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ command('tab split')
+ screen:expect([[
+ {4: }{5:2}{4:+ [No Name] }{2: + [No Name] }{3: }{4:X}|
+ ^foo |
+ foo |
+ foo |
+ foo |
+ bar |
+ bar |
+ bar |
+ bar |
+ bar |
+ bar |
+ bar |
+ bar |
+ |
+ ]])
+ end)
+
+ it('redraws unvisited tab #9152', function()
+ insert('hello')
+ -- create a tab without visiting it
+ command('tabnew|tabnext')
+ screen:expect([[
+ {2: + [No Name] }{4: [No Name] }{3: }{4:X}|
+ hell^o |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('gT')
+ screen:expect([[
+ {4: + [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
end)
end)
@@ -741,4 +875,12 @@ describe('Screen', function()
|
]])
end)
+end
+
+describe("Screen (char-based)", function()
+ screen_tests(false)
+end)
+
+describe("Screen (line-based)", function()
+ screen_tests(true)
end)
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 168080a092..a46670d8a2 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
+local command = helpers.command
local feed_command = helpers.feed_command
local eq = helpers.eq
local eval = helpers.eval
@@ -93,6 +94,59 @@ describe('search highlighting', function()
]])
end)
+ it('highlights after EOL', function()
+ insert("\n\n\n\n\n\n")
+
+ feed("gg/^<cr>")
+ screen:expect([[
+ {2: } |
+ {2:^ } |
+ {2: } |
+ {2: } |
+ {2: } |
+ {2: } |
+ /^ |
+ ]])
+
+ -- Test that highlights are preserved after moving the cursor.
+ feed("j")
+ screen:expect([[
+ {2: } |
+ {2: } |
+ {2:^ } |
+ {2: } |
+ {2: } |
+ {2: } |
+ /^ |
+ ]])
+
+ -- Repeat the test in rightleft mode.
+ command("nohlsearch")
+ command("set rightleft")
+ feed("gg/^<cr>")
+
+ screen:expect([[
+ {2: }|
+ {2:^ }|
+ {2: }|
+ {2: }|
+ {2: }|
+ {2: }|
+ ^/ |
+ ]])
+
+ feed("j")
+ screen:expect([[
+ {2: }|
+ {2: }|
+ {2:^ }|
+ {2: }|
+ {2: }|
+ {2: }|
+ ^/ |
+ ]])
+ end)
+
it('is preserved during :terminal activity', function()
if iswin() then
feed([[:terminal for /L \%I in (1,1,5000) do @(echo xxx & echo xxx & echo xxx)<cr>]])
@@ -270,7 +324,17 @@ describe('search highlighting', function()
]])
-- same, for C-t
- feed('<ESC>/<C-t>')
+ feed('<ESC>')
+ screen:expect([[
+ the first line |
+ in a ^little file |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('/<C-t>')
screen:expect([[
the first line |
in a little file |
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index c00d99cf90..6abeb0b2f4 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
+local source = helpers.source
describe('Signs', function()
local screen
@@ -13,6 +14,12 @@ describe('Signs', function()
[0] = {bold=true, foreground=255},
[1] = {background = Screen.colors.Yellow},
[2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Grey},
+ [3] = {background = Screen.colors.Gray90},
+ [4] = {bold = true, reverse = true},
+ [5] = {reverse = true},
+ [6] = {foreground = Screen.colors.Brown},
+ [7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
+ [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
} )
end)
@@ -45,5 +52,64 @@ describe('Signs', function()
|
]])
end)
+
+ it('can be called right after :split', function()
+ feed('ia<cr>b<cr>c<cr><esc>gg')
+ -- This used to cause a crash due to :sign using a special redraw
+ -- (not updating nvim's specific highlight data structures)
+ -- without proper redraw first, as split just flags for redraw later.
+ source([[
+ set cursorline
+ sign define piet text=>> texthl=Search
+ split
+ sign place 3 line=2 name=piet buffer=1
+ ]])
+ screen:expect([[
+ {2: }{3:^a }|
+ {1:>>}b |
+ {2: }c |
+ {2: } |
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {4:[No Name] [+] }|
+ {2: }{3:a }|
+ {1:>>}b |
+ {2: }c |
+ {2: } |
+ {2: }{0:~ }|
+ {5:[No Name] [+] }|
+ |
+ ]])
+ end)
+
+ it('can combine text, linehl and numhl', function()
+ feed('ia<cr>b<cr>c<cr><esc>')
+ command('set number')
+ command('sign define piet text=>> texthl=Search')
+ command('sign define pietx linehl=ErrorMsg')
+ command('sign define pietxx numhl=Folded')
+ command('sign place 1 line=1 name=piet buffer=1')
+ command('sign place 2 line=2 name=pietx buffer=1')
+ command('sign place 3 line=3 name=pietxx buffer=1')
+ command('sign place 4 line=4 name=piet buffer=1')
+ command('sign place 5 line=4 name=pietx buffer=1')
+ command('sign place 6 line=4 name=pietxx buffer=1')
+ screen:expect([[
+ {1:>>}{6: 1 }a |
+ {2: }{6: 2 }{8:b }|
+ {2: }{7: 3 }c |
+ {1:>>}{7: 4 }{8:^ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ |
+ ]])
+ end)
end)
end)
diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua
index e8271de0bf..dcab9f7ef4 100644
--- a/test/functional/ui/tabline_spec.lua
+++ b/test/functional/ui/tabline_spec.lua
@@ -28,27 +28,27 @@ describe('ui/ext_tabline', function()
{tab = { id = 1 }, name = '[No Name]'},
{tab = { id = 2 }, name = 'another-tab'},
}
- screen:expect([[
+ screen:expect{grid=[[
^ |
~ |
~ |
~ |
|
- ]], nil, nil, function()
+ ]], condition=function()
eq({ id = 2 }, event_curtab)
eq(expected_tabs, event_tabs)
- end)
+ end}
command("tabNext")
- screen:expect([[
+ screen:expect{grid=[[
^ |
~ |
~ |
~ |
|
- ]], nil, nil, function()
+ ]], condition=function()
eq({ id = 1 }, event_curtab)
eq(expected_tabs, event_tabs)
- end)
+ end}
end)
end)
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index b60d520ca0..8931d9245b 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -1,3 +1,5 @@
+local global_helpers = require('test.helpers')
+local shallowcopy = global_helpers.shallowcopy
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
@@ -18,6 +20,14 @@ describe("'wildmenu'", function()
screen:detach()
end)
+ -- expect the screen stayed unchanged some time after first seen success
+ local function expect_stay_unchanged(args)
+ screen:expect(args)
+ args = shallowcopy(args)
+ args.unchanged = true
+ screen:expect(args)
+ end
+
it(':sign <tab> shows wildmenu completions', function()
command('set wildmode=full')
command('set wildmenu')
@@ -76,10 +86,6 @@ describe("'wildmenu'", function()
end)
it('is preserved during :terminal activity', function()
- -- Because this test verifies a _lack_ of activity after screen:sleep(), we
- -- must wait the full timeout. So make it reasonable.
- screen.timeout = 1000
-
command('set wildmenu wildmode=full')
command('set scrollback=4')
if iswin() then
@@ -90,26 +96,24 @@ describe("'wildmenu'", function()
feed([[<C-\><C-N>gg]])
feed([[:sign <Tab>]]) -- Invoke wildmenu.
- screen:sleep(50) -- Allow some terminal output.
- screen:expect([[
+ expect_stay_unchanged{grid=[[
foo |
foo |
foo |
define jump list > |
:sign define^ |
- ]])
+ ]]}
-- cmdline CTRL-D display should also be preserved.
feed([[<C-\><C-N>]])
feed([[:sign <C-D>]]) -- Invoke cmdline CTRL-D.
- screen:sleep(50) -- Allow some terminal output.
- screen:expect([[
+ expect_stay_unchanged{grid=[[
:sign |
define place |
jump undefine |
list unplace |
:sign ^ |
- ]])
+ ]]}
-- Exiting cmdline should show the buffer.
feed([[<C-\><C-N>]])
@@ -123,22 +127,17 @@ describe("'wildmenu'", function()
end)
it('ignores :redrawstatus called from a timer #7108', function()
- -- Because this test verifies a _lack_ of activity after screen:sleep(), we
- -- must wait the full timeout. So make it reasonable.
- screen.timeout = 1000
-
command('set wildmenu wildmode=full')
command([[call timer_start(10, {->execute('redrawstatus')}, {'repeat':-1})]])
feed([[<C-\><C-N>]])
feed([[:sign <Tab>]]) -- Invoke wildmenu.
- screen:sleep(30) -- Allow some timer activity.
- screen:expect([[
+ expect_stay_unchanged{grid=[[
|
~ |
~ |
define jump list > |
:sign define^ |
- ]])
+ ]]}
end)
it('with laststatus=0, :vsplit, :term #2255', function()
@@ -164,10 +163,9 @@ describe("'wildmenu'", function()
feed([[<C-\><C-N>]])
feed([[:<Tab>]]) -- Invoke wildmenu.
- screen:sleep(10) -- Flush
-- Check only the last 2 lines, because the shell output is
-- system-dependent.
- screen:expect('! # & < = > @ > \n:!^', nil, nil, nil, true)
+ expect_stay_unchanged{any='! # & < = > @ > \n:!^'}
end)
end)
@@ -204,21 +202,11 @@ end)
describe('ui/ext_wildmenu', function()
local screen
- local items, selected = nil, nil
before_each(function()
clear()
screen = Screen.new(25, 5)
screen:attach({rgb=true, ext_wildmenu=true})
- screen:set_on_event_handler(function(name, data)
- if name == "wildmenu_show" then
- items = data[1]
- elseif name == "wildmenu_select" then
- selected = data[1]
- elseif name == "wildmenu_hide" then
- items, selected = nil, nil
- end
- end)
end)
after_each(function()
@@ -238,63 +226,48 @@ describe('ui/ext_wildmenu', function()
command('set wildmode=full')
command('set wildmenu')
feed(':sign <tab>')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign define^ |
- ]], nil, nil, function()
- eq(expected, items)
- eq(0, selected)
- end)
+ ]], wildmenu_items=expected, wildmenu_pos=0}
feed('<tab>')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign jump^ |
- ]], nil, nil, function()
- eq(expected, items)
- eq(1, selected)
- end)
+ ]], wildmenu_items=expected, wildmenu_pos=1}
feed('<left><left>')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign ^ |
- ]], nil, nil, function()
- eq(expected, items)
- eq(-1, selected)
- end)
+ ]], wildmenu_items=expected, wildmenu_pos=-1}
feed('<right>')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign define^ |
- ]], nil, nil, function()
- eq(expected, items)
- eq(0, selected)
- end)
+ ]], wildmenu_items=expected, wildmenu_pos=0}
feed('a')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign definea^ |
- ]], nil, nil, function()
- eq(nil, items)
- eq(nil, selected)
- end)
+ ]]}
end)
end)