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.lua208
-rw-r--r--test/functional/ui/highlight_spec.lua365
-rw-r--r--test/functional/ui/inccommand_spec.lua1623
-rw-r--r--test/functional/ui/input_spec.lua4
-rw-r--r--test/functional/ui/mouse_spec.lua799
-rw-r--r--test/functional/ui/output_spec.lua68
-rw-r--r--test/functional/ui/quickfix_spec.lua196
-rw-r--r--test/functional/ui/screen.lua206
-rw-r--r--test/functional/ui/screen_basic_spec.lua562
-rw-r--r--test/functional/ui/searchhl_spec.lua201
-rw-r--r--test/functional/ui/sign_spec.lua36
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua186
-rw-r--r--test/functional/ui/wildmode_spec.lua12
13 files changed, 3557 insertions, 909 deletions
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 58f5b11de0..53fe303762 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -1,39 +1,31 @@
-local helpers = require('test.functional.helpers')
+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 execute, request, neq = helpers.execute, helpers.request, helpers.neq
+if helpers.pending_win32(pending) then return end
describe('Buffer highlighting', function()
local screen
local curbuf
- local hl_colors = {
- NonText = Screen.colors.Blue,
- Question = Screen.colors.SeaGreen,
- String = Screen.colors.Fuchsia,
- Statement = Screen.colors.Brown,
- Special = Screen.colors.SlateBlue,
- Identifier = Screen.colors.DarkCyan
- }
-
before_each(function()
clear()
execute("syntax on")
screen = Screen.new(40, 8)
screen:attach()
- screen:set_default_attr_ignore( {{bold=true, foreground=hl_colors.NonText}} )
screen:set_default_attr_ids({
- [1] = {foreground = hl_colors.String},
- [2] = {foreground = hl_colors.Statement, bold = true},
- [3] = {foreground = hl_colors.Special},
- [4] = {bold = true, foreground = hl_colors.Special},
- [5] = {foreground = hl_colors.Identifier},
- [6] = {bold = true},
- [7] = {underline = true, bold = true, foreground = hl_colors.Special},
- [8] = {foreground = hl_colors.Special, underline = true}
+ [1] = {bold=true, foreground=Screen.colors.Blue},
+ [2] = {foreground = Screen.colors.Fuchsia}, -- String
+ [3] = {foreground = Screen.colors.Brown, bold = true}, -- Statement
+ [4] = {foreground = Screen.colors.SlateBlue}, -- Special
+ [5] = {bold = true, foreground = Screen.colors.SlateBlue},
+ [6] = {foreground = Screen.colors.DarkCyan}, -- Identifier
+ [7] = {bold = true},
+ [8] = {underline = true, bold = true, foreground = Screen.colors.SlateBlue},
+ [9] = {foreground = Screen.colors.SlateBlue, underline = true}
})
- curbuf = request('vim_get_current_buffer')
+ curbuf = request('nvim_get_current_buf')
end)
after_each(function()
@@ -41,11 +33,11 @@ describe('Buffer highlighting', function()
end)
local function add_hl(...)
- return request('buffer_add_highlight', curbuf, ...)
+ return request('nvim_buf_add_highlight', curbuf, ...)
end
local function clear_hl(...)
- return request('buffer_clear_highlight', curbuf, ...)
+ return request('nvim_buf_clear_highlight', curbuf, ...)
end
@@ -58,11 +50,11 @@ describe('Buffer highlighting', function()
screen:expect([[
these are some lines |
with colorful tex^t |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]])
@@ -70,25 +62,25 @@ describe('Buffer highlighting', function()
add_hl(-1, "Statement", 1 , 5, -1)
screen:expect([[
- these are {1:some} lines |
- with {2:colorful tex^t} |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ these are {2:some} lines |
+ with {3:colorful tex^t} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]])
feed("ggo<esc>")
screen:expect([[
- these are {1:some} lines |
+ these are {2:some} lines |
^ |
- with {2:colorful text} |
- ~ |
- ~ |
- ~ |
- ~ |
+ with {3:colorful text} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]])
@@ -97,10 +89,10 @@ describe('Buffer highlighting', function()
these are some lines |
^ |
with colorful text |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]])
end)
@@ -120,21 +112,25 @@ describe('Buffer highlighting', function()
add_hl(id1, "ImportantWord", 2, 0, 9)
add_hl(id1, "ImportantWord", 3, 5, 14)
- id2 = add_hl(0, "Special", 0, 2, 8)
+ -- add_highlight can be called like this to get a new source
+ -- without adding any highlight
+ id2 = add_hl(0, "", 0, 0, 0)
+ neq(id1, id2)
+
+ add_hl(id2, "Special", 0, 2, 8)
add_hl(id2, "Identifier", 1, 3, 8)
add_hl(id2, "Special", 1, 14, 20)
add_hl(id2, "Underlined", 2, 6, 12)
add_hl(id2, "Underlined", 3, 0, 9)
- neq(id1, id2)
screen:expect([[
- a {4:longer} example |
- in {5:order} to {6:de}{4:monstr}{6:ate} |
- {6:combin}{7:ing}{8: hi}ghlights |
- {8:from }{7:diff}{6:erent} source^s |
- ~ |
- ~ |
- ~ |
+ a {5:longer} example |
+ in {6:order} to {7:de}{5:monstr}{7:ate} |
+ {7:combin}{8:ing}{9: hi}ghlights |
+ {9:from }{8:diff}{7:erent} source^s |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
:hi ImportantWord gui=bold cterm=bold |
]])
end)
@@ -142,13 +138,13 @@ describe('Buffer highlighting', function()
it('and clearing the first added', function()
clear_hl(id1, 0, -1)
screen:expect([[
- a {3:longer} example |
- in {5:order} to de{3:monstr}ate |
- combin{8:ing hi}ghlights |
- {8:from diff}erent source^s |
- ~ |
- ~ |
- ~ |
+ a {4:longer} example |
+ in {6:order} to de{4:monstr}ate |
+ combin{9:ing hi}ghlights |
+ {9:from diff}erent source^s |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
:hi ImportantWord gui=bold cterm=bold |
]])
end)
@@ -156,13 +152,13 @@ describe('Buffer highlighting', function()
it('and clearing the second added', function()
clear_hl(id2, 0, -1)
screen:expect([[
- a {6:longer} example |
- in order to {6:demonstrate} |
- {6:combining} highlights |
- from {6:different} source^s |
- ~ |
- ~ |
- ~ |
+ a {7:longer} example |
+ in order to {7:demonstrate} |
+ {7:combining} highlights |
+ from {7:different} source^s |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
:hi ImportantWord gui=bold cterm=bold |
]])
end)
@@ -173,12 +169,12 @@ describe('Buffer highlighting', function()
clear_hl(id2, 2, -1)
screen:expect([[
a longer example |
- in {5:order} to de{3:monstr}ate |
- {6:combining} highlights |
- from {6:different} source^s |
- ~ |
- ~ |
- ~ |
+ in {6:order} to de{4:monstr}ate |
+ {7:combining} highlights |
+ from {7:different} source^s |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
:hi ImportantWord gui=bold cterm=bold |
]])
end)
@@ -186,25 +182,25 @@ describe('Buffer highlighting', function()
it('and renumbering lines', function()
feed('3Gddggo<esc>')
screen:expect([[
- a {4:longer} example |
+ a {5:longer} example |
^ |
- in {5:order} to {6:de}{4:monstr}{6:ate} |
- {8:from }{7:diff}{6:erent} sources |
- ~ |
- ~ |
- ~ |
+ in {6:order} to {7:de}{5:monstr}{7:ate} |
+ {9:from }{8:diff}{7:erent} sources |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]])
execute(':3move 4')
screen:expect([[
- a {4:longer} example |
+ a {5:longer} example |
|
- {8:from }{7:diff}{6:erent} sources |
- ^in {5:order} to {6:de}{4:monstr}{6:ate} |
- ~ |
- ~ |
- ~ |
+ {9:from }{8:diff}{7:erent} sources |
+ ^in {6:order} to {7:de}{5:monstr}{7:ate} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
::3move 4 |
]])
end)
@@ -218,25 +214,25 @@ describe('Buffer highlighting', function()
local id = add_hl(0, "Special", 0, 0, 9)
screen:expect([[
- {3:three ove}{5:rlapp}{1:ing color}^s |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {4:three ove}{6:rlapp}{2:ing color}^s |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]])
clear_hl(id, 0, 1)
screen:expect([[
- three {5:overlapp}{1:ing color}^s |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ three {6:overlapp}{2:ing color}^s |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]])
end)
@@ -248,13 +244,13 @@ describe('Buffer highlighting', function()
add_hl(-1, "String", 0, 16, 21)
screen:expect([[
- Ta {5:båten} över {1:sjön}^! |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ Ta {6:båten} över {2:sjön}^! |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]])
end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 85fca4d7ca..945b16ef92 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -1,9 +1,10 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local os = require('os')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local execute, request, eq = helpers.execute, helpers.request, helpers.eq
+if helpers.pending_win32(pending) then return end
describe('color scheme compatibility', function()
before_each(function()
@@ -12,7 +13,7 @@ describe('color scheme compatibility', function()
it('t_Co is set to 256 by default', function()
eq('256', request('vim_eval', '&t_Co'))
- request('vim_set_option', 't_Co', '88')
+ request('nvim_set_option', 't_Co', '88')
eq('88', request('vim_eval', '&t_Co'))
end)
end)
@@ -27,10 +28,11 @@ describe('manual syntax highlight', function()
clear()
screen = Screen.new(20,5)
screen:attach()
- --ignore highligting of ~-lines
- screen:set_default_attr_ignore( {{bold=true, foreground=Screen.colors.Blue}} )
--syntax highlight for vimcscripts "echo"
- screen:set_default_attr_ids( {[1] = {bold=true, foreground=Screen.colors.Brown}} )
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {bold=true, foreground=Screen.colors.Brown}
+ } )
end)
after_each(function()
@@ -38,7 +40,6 @@ describe('manual syntax highlight', function()
os.remove('Xtest-functional-ui-highlight.tmp.vim')
end)
- -- test with "set hidden" even if the bug did not occur this way
it("works with buffer switch and 'hidden'", function()
execute('e tmp1.vim')
execute('e Xtest-functional-ui-highlight.tmp.vim')
@@ -54,9 +55,9 @@ describe('manual syntax highlight', function()
execute('bp')
screen:expect([[
{1:^echo} 1 |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
<f 1 --100%-- col 1 |
]])
end)
@@ -76,9 +77,9 @@ describe('manual syntax highlight', function()
execute('bp')
screen:expect([[
{1:^echo} 1 |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
<ht.tmp.vim" 1L, 7C |
]])
end)
@@ -90,17 +91,10 @@ describe('Default highlight groups', function()
-- command
local screen
- local hlgroup_colors = {
- NonText = Screen.colors.Blue,
- Question = Screen.colors.SeaGreen
- }
-
before_each(function()
clear()
screen = Screen.new()
screen:attach()
- --ignore highligting of ~-lines
- screen:set_default_attr_ignore( {{bold=true, foreground=hlgroup_colors.NonText}} )
end)
after_each(function()
@@ -109,23 +103,24 @@ describe('Default highlight groups', function()
it('window status bar', function()
screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {reverse = true, bold = true}, -- StatusLine
[2] = {reverse = true} -- StatusLineNC
})
execute('sp', 'vsp', 'vsp')
screen:expect([[
^ {2:|} {2:|} |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
{1:[No Name] }{2:[No Name] [No Name] }|
|
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
{2:[No Name] }|
|
]])
@@ -133,17 +128,17 @@ describe('Default highlight groups', function()
feed('<c-w>j')
screen:expect([[
{2:|} {2:|} |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
{2:[No Name] [No Name] [No Name] }|
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
{1:[No Name] }|
|
]])
@@ -153,51 +148,51 @@ describe('Default highlight groups', function()
feed('<c-w>k<c-w>l')
screen:expect([[
{2:|}^ {2:|} |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
{2:[No Name] }{1:[No Name] }{2:[No Name] }|
|
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
{2:[No Name] }|
|
]])
feed('<c-w>l')
screen:expect([[
{2:|} {2:|}^ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
{2:[No Name] [No Name] }{1:[No Name] }|
|
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
{2:[No Name] }|
|
]])
feed('<c-w>h<c-w>h')
screen:expect([[
^ {2:|} {2:|} |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
- ~ {2:|}~ {2:|}~ |
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }{2:|}{0:~ }|
{1:[No Name] }{2:[No Name] [No Name] }|
|
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
{2:[No Name] }|
|
]])
@@ -207,20 +202,21 @@ describe('Default highlight groups', function()
feed('i')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
{1:-- INSERT --} |
- ]], {[1] = {bold = true}})
+ ]], {[0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {bold = true}})
end)
it('end of file markers', function()
@@ -239,27 +235,28 @@ describe('Default highlight groups', function()
{1:~ }|
{1:~ }|
|
- ]], {[1] = {bold = true, foreground = hlgroup_colors.NonText}})
+ ]], {[1] = {bold = true, foreground = Screen.colors.Blue}})
end)
it('"wait return" text', function()
feed(':ls<cr>')
screen:expect([[
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:ls |
1 %a "[No Name]" line 1 |
{1:Press ENTER or type command to continue}^ |
- ]], {[1] = {bold = true, foreground = hlgroup_colors.Question}})
+ ]], {[0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen}})
feed('<cr>') -- skip the "Press ENTER..." state or tests will hang
end)
it('can be cleared and linked to other highlight groups', function()
@@ -267,40 +264,42 @@ describe('Default highlight groups', function()
feed('i')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
-- INSERT -- |
- ]], {})
+ ]], {[0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {bold=true}})
feed('<esc>')
execute('highlight CustomHLGroup guifg=red guibg=green')
execute('highlight link ModeMsg CustomHLGroup')
feed('i')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
{1:-- INSERT --} |
- ]], {[1] = {foreground = Screen.colors.Red, background = Screen.colors.Green}})
+ ]], {[0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {foreground = Screen.colors.Red, background = Screen.colors.Green}})
end)
it('can be cleared by assigning NONE', function()
execute('syn keyword TmpKeyword neovim')
@@ -308,40 +307,41 @@ describe('Default highlight groups', function()
insert('neovim')
screen:expect([[
{1:neovi^m} |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
|
]], {
+ [0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {foreground = Screen.colors.White, background = Screen.colors.Red}
})
execute("hi ErrorMsg term=NONE cterm=NONE ctermfg=NONE ctermbg=NONE"
.. " gui=NONE guifg=NONE guibg=NONE guisp=NONE")
screen:expect([[
neovi^m |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
|
- ]], {})
+ ]], {[0] = {bold=true, foreground=Screen.colors.Blue}})
end)
end)
@@ -352,10 +352,6 @@ describe('guisp (special/undercurl)', function()
clear()
screen = Screen.new(25,10)
screen:attach()
- screen:set_default_attr_ignore({
- [1] = {bold = true, foreground = Screen.colors.Blue},
- [2] = {bold = true}
- })
end)
it('can be set and is applied like foreground or background', function()
@@ -390,14 +386,16 @@ describe('guisp (special/undercurl)', function()
{4:specialwithfg} |
|
{1:neovim} tabbed^ |
- ~ |
- -- INSERT -- |
+ {0:~ }|
+ {5:-- INSERT --} |
]],{
+ [0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {background = Screen.colors.Yellow, foreground = Screen.colors.Red,
special = Screen.colors.Red},
[2] = {special = Screen.colors.Red},
[3] = {special = Screen.colors.Red, background = Screen.colors.Yellow},
[4] = {foreground = Screen.colors.Red, special = Screen.colors.Red},
+ [5] = {bold=true},
})
end)
@@ -406,13 +404,6 @@ end)
describe("'cursorline' with 'listchars'", function()
local screen
- local hlgroup_colors = {
- NonText = Screen.colors.Blue,
- Cursorline = Screen.colors.Grey90,
- SpecialKey = Screen.colors.Red,
- Visual = Screen.colors.LightGrey,
- }
-
before_each(function()
clear()
screen = Screen.new(20,5)
@@ -424,48 +415,50 @@ describe("'cursorline' with 'listchars'", function()
end)
it("'cursorline' and 'cursorcolumn'", function()
- screen:set_default_attr_ids({[1] = {background=hlgroup_colors.Cursorline}})
- screen:set_default_attr_ignore( {{bold=true, foreground=hlgroup_colors.NonText}} )
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {background=Screen.colors.Grey90}
+ })
execute('highlight clear ModeMsg')
execute('set cursorline')
feed('i')
screen:expect([[
{1:^ }|
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
-- INSERT -- |
]])
feed('abcdefg<cr>kkasdf')
screen:expect([[
abcdefg |
{1:kkasdf^ }|
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
-- INSERT -- |
]])
feed('<esc>')
screen:expect([[
abcdefg |
{1:kkasd^f }|
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
|
]])
execute('set nocursorline')
screen:expect([[
abcdefg |
kkasd^f |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
:set nocursorline |
]])
feed('k')
screen:expect([[
abcde^fg |
kkasdf |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
:set nocursorline |
]])
feed('jjji<cr><cr><cr><esc>')
@@ -498,22 +491,22 @@ describe("'cursorline' with 'listchars'", function()
it("'cursorline' and with 'listchar' option: space, eol, tab, and trail", function()
screen:set_default_attr_ids({
- [1] = {background=hlgroup_colors.Cursorline},
+ [1] = {background=Screen.colors.Grey90},
[2] = {
- foreground=hlgroup_colors.SpecialKey,
- background=hlgroup_colors.Cursorline,
+ foreground=Screen.colors.Red,
+ background=Screen.colors.Grey90,
},
[3] = {
- background=hlgroup_colors.Cursorline,
- foreground=hlgroup_colors.NonText,
+ background=Screen.colors.Grey90,
+ foreground=Screen.colors.Blue,
bold=true,
},
[4] = {
- foreground=hlgroup_colors.NonText,
+ foreground=Screen.colors.Blue,
bold=true,
},
[5] = {
- foreground=hlgroup_colors.SpecialKey,
+ foreground=Screen.colors.Red,
},
})
execute('highlight clear ModeMsg')
@@ -582,33 +575,33 @@ describe("'cursorline' with 'listchars'", function()
it("'listchar' in visual mode", function()
screen:set_default_attr_ids({
- [1] = {background=hlgroup_colors.Cursorline},
+ [1] = {background=Screen.colors.Grey90},
[2] = {
- foreground=hlgroup_colors.SpecialKey,
- background=hlgroup_colors.Cursorline,
+ foreground=Screen.colors.Red,
+ background=Screen.colors.Grey90,
},
[3] = {
- background=hlgroup_colors.Cursorline,
- foreground=hlgroup_colors.NonText,
+ background=Screen.colors.Grey90,
+ foreground=Screen.colors.Blue,
bold=true,
},
[4] = {
- foreground=hlgroup_colors.NonText,
+ foreground=Screen.colors.Blue,
bold=true,
},
[5] = {
- foreground=hlgroup_colors.SpecialKey,
+ foreground=Screen.colors.Red,
},
[6] = {
- background=hlgroup_colors.Visual,
+ background=Screen.colors.LightGrey,
},
[7] = {
- background=hlgroup_colors.Visual,
- foreground=hlgroup_colors.SpecialKey,
+ background=Screen.colors.LightGrey,
+ foreground=Screen.colors.Red,
},
[8] = {
- background=hlgroup_colors.Visual,
- foreground=hlgroup_colors.NonText,
+ background=Screen.colors.LightGrey,
+ foreground=Screen.colors.Blue,
bold=true,
},
})
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
new file mode 100644
index 0000000000..6da22b6a3a
--- /dev/null
+++ b/test/functional/ui/inccommand_spec.lua
@@ -0,0 +1,1623 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local curbufmeths = helpers.curbufmeths
+local eq = helpers.eq
+local eval = helpers.eval
+local execute = helpers.execute
+local expect = helpers.expect
+local feed = helpers.feed
+local insert = helpers.insert
+local meths = helpers.meths
+local neq = helpers.neq
+local ok = helpers.ok
+local source = helpers.source
+local wait = helpers.wait
+
+local default_text = [[
+ Inc substitution on
+ two lines
+]]
+
+local function common_setup(screen, inccommand, text)
+ if screen then
+ execute("syntax on")
+ execute("set nohlsearch")
+ execute("hi Substitute guifg=red guibg=yellow")
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.Fuchsia},
+ [2] = {foreground = Screen.colors.Brown, bold = true},
+ [3] = {foreground = Screen.colors.SlateBlue},
+ [4] = {bold = true, foreground = Screen.colors.SlateBlue},
+ [5] = {foreground = Screen.colors.DarkCyan},
+ [6] = {bold = true},
+ [7] = {underline = true, bold = true, foreground = Screen.colors.SlateBlue},
+ [8] = {foreground = Screen.colors.Slateblue, underline = true},
+ [9] = {background = Screen.colors.Yellow},
+ [10] = {reverse = true},
+ [11] = {reverse = true, bold=true},
+ [12] = {foreground = Screen.colors.Red, background = Screen.colors.Yellow},
+ [13] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [14] = {foreground = Screen.colors.White, background = Screen.colors.Red},
+ [15] = {bold=true, foreground=Screen.colors.Blue},
+ [16] = {background=Screen.colors.Grey90}, -- cursorline
+ vis = {background=Screen.colors.LightGrey}
+ })
+ end
+
+ execute("set inccommand=" .. (inccommand and inccommand or ""))
+
+ if text then
+ insert(text)
+ end
+end
+
+describe(":substitute, inccommand=split does not trigger preview", function()
+ before_each(function()
+ clear()
+ common_setup(nil, "split", default_text)
+ end)
+
+ it("if invoked by a script ", function()
+ source('%s/tw/MO/g')
+ wait()
+ eq(1, eval("bufnr('$')"))
+
+ -- sanity check: assert the buffer state
+ expect(default_text:gsub("tw", "MO"))
+ end)
+
+ it("if invoked by feedkeys()", function()
+ -- in a script...
+ source([[:call feedkeys(":%s/tw/MO/g\<CR>")]])
+ wait()
+ -- or interactively...
+ feed([[:call feedkeys(":%s/tw/MO/g\<CR>")<CR>]])
+ wait()
+ eq(1, eval("bufnr('$')"))
+
+ -- sanity check: assert the buffer state
+ expect(default_text:gsub("tw", "MO"))
+ end)
+end)
+
+describe(":substitute, 'inccommand' preserves", function()
+ if helpers.pending_win32(pending) then return end
+
+ before_each(clear)
+
+ it('listed buffers (:ls)', function()
+ local screen = Screen.new(30,10)
+ common_setup(screen, "split", "ABC")
+
+ execute("%s/AB/BA/")
+ execute("ls")
+
+ screen:expect([[
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :ls |
+ 1 %a + "[No Name]" |
+ line 1 |
+ {13:Press ENTER or type command to}|
+ {13: continue}^ |
+ ]])
+ end)
+
+ for _, case in pairs{"", "split", "nosplit"} do
+ it("various delimiters (inccommand="..case..")", function()
+ insert(default_text)
+ execute("set inccommand=" .. case)
+
+ local delims = { '/', '#', ';', '%', ',', '@', '!', ''}
+ for _,delim in pairs(delims) do
+ execute("%s"..delim.."lines"..delim.."LINES"..delim.."g")
+ expect([[
+ Inc substitution on
+ two LINES
+ ]])
+ execute("undo")
+ end
+ end)
+ end
+
+ for _, case in pairs{"", "split", "nosplit"} do
+ it("'undolevels' (inccommand="..case..")", function()
+ execute("set undolevels=139")
+ execute("setlocal undolevels=34")
+ execute("set inccommand=" .. case)
+ insert("as")
+ feed(":%s/as/glork/<enter>")
+ eq(meths.get_option('undolevels'), 139)
+ eq(curbufmeths.get_option('undolevels'), 34)
+ end)
+ end
+
+ for _, case in ipairs({"", "split", "nosplit"}) do
+ it("empty undotree() (inccommand="..case..")", function()
+ execute("set undolevels=1000")
+ execute("set inccommand=" .. case)
+ local expected_undotree = eval("undotree()")
+
+ -- Start typing an incomplete :substitute command.
+ feed([[:%s/e/YYYY/g]])
+ wait()
+ -- Cancel the :substitute.
+ feed([[<C-\><C-N>]])
+
+ -- The undo tree should be unchanged.
+ eq(expected_undotree, eval("undotree()"))
+ eq({}, eval("undotree()")["entries"])
+ end)
+ end
+
+ for _, case in ipairs({"", "split", "nosplit"}) do
+ it("undotree() with branches (inccommand="..case..")", function()
+ execute("set undolevels=1000")
+ execute("set inccommand=" .. case)
+ -- Make some changes.
+ feed([[isome text 1<C-\><C-N>]])
+ feed([[osome text 2<C-\><C-N>]])
+ -- Add an undo branch.
+ feed([[u]])
+ -- More changes, more undo branches.
+ feed([[osome text 3<C-\><C-N>]])
+ feed([[AX<C-\><C-N>]])
+ feed([[...]])
+ feed([[uu]])
+ feed([[osome text 4<C-\><C-N>]])
+ feed([[u<C-R>u]])
+ feed([[osome text 5<C-\><C-N>]])
+ expect([[
+ some text 1
+ some text 3XX
+ some text 5]])
+ local expected_undotree = eval("undotree()")
+ eq(5, #expected_undotree["entries"]) -- sanity
+
+ -- Start typing an incomplete :substitute command.
+ feed([[:%s/e/YYYY/g]])
+ wait()
+ -- Cancel the :substitute.
+ feed([[<C-\><C-N>]])
+
+ -- The undo tree should be unchanged.
+ eq(expected_undotree, eval("undotree()"))
+ end)
+ end
+
+ for _, case in pairs{"", "split", "nosplit"} do
+ it("b:changedtick (inccommand="..case..")", function()
+ execute("set inccommand=" .. case)
+ feed([[isome text 1<C-\><C-N>]])
+ feed([[osome text 2<C-\><C-N>]])
+ local expected_tick = eval("b:changedtick")
+ ok(expected_tick > 0)
+
+ expect([[
+ some text 1
+ some text 2]])
+ feed(":%s/e/XXX/")
+ wait()
+
+ eq(expected_tick, eval("b:changedtick"))
+ end)
+ end
+
+ for _, case in pairs{"", "split", "nosplit"} do
+ it("visual selection for non-previewable command (inccommand="..case..") #5888", function()
+ local screen = Screen.new(30,10)
+ common_setup(screen, case, default_text)
+ feed('1G2V')
+
+ feed(':s')
+ screen:expect([[
+ {vis:Inc substitution on} |
+ t{vis:wo lines} |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :'<,'>s^ |
+ ]])
+
+ feed('o')
+ screen:expect([[
+ {vis:Inc substitution on} |
+ t{vis:wo lines} |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :'<,'>so^ |
+ ]])
+ end)
+ end
+
+end)
+
+describe(":substitute, 'inccommand' preserves undo", function()
+ if helpers.pending_win32(pending) then return end
+
+ local cases = { "", "split", "nosplit" }
+
+ local substrings = {
+ ":%s/1",
+ ":%s/1/",
+ ":%s/1/<bs>",
+ ":%s/1/a",
+ ":%s/1/a<bs>",
+ ":%s/1/ax",
+ ":%s/1/ax<bs>",
+ ":%s/1/ax<bs><bs>",
+ ":%s/1/ax<bs><bs><bs>",
+ ":%s/1/ax/",
+ ":%s/1/ax/<bs>",
+ ":%s/1/ax/<bs>/",
+ ":%s/1/ax/g",
+ ":%s/1/ax/g<bs>",
+ ":%s/1/ax/g<bs><bs>"
+ }
+
+ local function test_sub(substring, split, redoable)
+ clear()
+ execute("set inccommand=" .. split)
+
+ insert("1")
+ feed("o2<esc>")
+ execute("undo")
+ feed("o3<esc>")
+ if redoable then
+ feed("o4<esc>")
+ execute("undo")
+ end
+ feed(substring.. "<enter>")
+ execute("undo")
+
+ feed("g-")
+ expect([[
+ 1
+ 2]])
+
+ feed("g+")
+ expect([[
+ 1
+ 3]])
+ end
+
+ local function test_notsub(substring, split, redoable)
+ clear()
+ execute("set inccommand=" .. split)
+
+ insert("1")
+ feed("o2<esc>")
+ execute("undo")
+ feed("o3<esc>")
+ if redoable then
+ feed("o4<esc>")
+ execute("undo")
+ end
+ feed(substring .. "<esc>")
+
+ feed("g-")
+ expect([[
+ 1
+ 2]])
+
+ feed("g+")
+ expect([[
+ 1
+ 3]])
+
+ if redoable then
+ feed("<c-r>")
+ expect([[
+ 1
+ 3
+ 4]])
+ end
+ end
+
+
+ local function test_threetree(substring, split)
+ clear()
+ execute("set inccommand=" .. split)
+
+ insert("1")
+ feed("o2<esc>")
+ feed("o3<esc>")
+ feed("uu")
+ feed("oa<esc>")
+ feed("ob<esc>")
+ feed("uu")
+ feed("oA<esc>")
+ feed("oB<esc>")
+
+ -- This is the undo tree (x-Axis is timeline), we're at B now
+ -- ----------------A - B
+ -- /
+ -- | --------a - b
+ -- |/
+ -- 1 - 2 - 3
+
+ feed("2u")
+ feed(substring .. "<esc>")
+ expect([[
+ 1]])
+ feed("g-")
+ expect([[
+ ]])
+ feed("g+")
+ expect([[
+ 1]])
+ feed("<c-r>")
+ expect([[
+ 1
+ A]])
+
+ feed("g-") -- go to b
+ feed("2u")
+ feed(substring .. "<esc>")
+ feed("<c-r>")
+ expect([[
+ 1
+ a]])
+
+ feed("g-") -- go to 3
+ feed("2u")
+ feed(substring .. "<esc>")
+ feed("<c-r>")
+ expect([[
+ 1
+ 2]])
+ end
+
+ it("at a non-leaf of the undo tree", function()
+ for _, case in pairs(cases) do
+ for _, str in pairs(substrings) do
+ for _, redoable in pairs({true}) do
+ test_sub(str, case, redoable)
+ end
+ end
+ end
+ end)
+
+ it("at a leaf of the undo tree", function()
+ for _, case in pairs(cases) do
+ for _, str in pairs(substrings) do
+ for _, redoable in pairs({false}) do
+ test_sub(str, case, redoable)
+ end
+ end
+ end
+ end)
+
+ it("when interrupting substitution", function()
+ for _, case in pairs(cases) do
+ for _, str in pairs(substrings) do
+ for _, redoable in pairs({true,false}) do
+ test_notsub(str, case, redoable)
+ end
+ end
+ end
+ end)
+
+ it("in a complex undo scenario", function()
+ for _, case in pairs(cases) do
+ for _, str in pairs(substrings) do
+ test_threetree(str, case)
+ end
+ end
+ end)
+
+ it('with undolevels=0', function()
+ for _, case in pairs(cases) do
+ clear()
+ common_setup(nil, case, default_text)
+ execute("set undolevels=0")
+
+ feed("1G0")
+ insert("X")
+ feed(":%s/tw/MO/<esc>")
+ execute("undo")
+ expect(default_text)
+ execute("undo")
+ expect(default_text:gsub("Inc", "XInc"))
+ execute("undo")
+
+ execute("%s/tw/MO/g")
+ expect(default_text:gsub("tw", "MO"))
+ execute("undo")
+ expect(default_text)
+ execute("undo")
+ expect(default_text:gsub("tw", "MO"))
+ end
+ end)
+
+ it('with undolevels=1', function()
+ local screen = Screen.new(20,10)
+
+ for _, case in pairs(cases) do
+ clear()
+ common_setup(screen, case, default_text)
+ execute("set undolevels=1")
+
+ feed("1G0")
+ insert("X")
+ feed("IY<esc>")
+ feed(":%s/tw/MO/<esc>")
+ -- execute("undo") here would cause "Press ENTER".
+ feed("u")
+ expect(default_text:gsub("Inc", "XInc"))
+ feed("u")
+ expect(default_text)
+
+ feed(":%s/tw/MO/g<enter>")
+ feed(":%s/MO/GO/g<enter>")
+ feed(":%s/GO/NO/g<enter>")
+ feed("u")
+ expect(default_text:gsub("tw", "GO"))
+ feed("u")
+ expect(default_text:gsub("tw", "MO"))
+ feed("u")
+
+ if case == "split" then
+ screen:expect([[
+ Inc substitution on |
+ ^MOo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ else
+ screen:expect([[
+ Inc substitution on |
+ ^MOo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ end
+ end
+ screen:detach()
+ end)
+
+ it('with undolevels=2', function()
+ local screen = Screen.new(20,10)
+
+ for _, case in pairs(cases) do
+ clear()
+ common_setup(screen, case, default_text)
+ execute("set undolevels=2")
+
+ feed("2GAx<esc>")
+ feed("Ay<esc>")
+ feed("Az<esc>")
+ feed(":%s/tw/AR<esc>")
+ -- using execute("undo") here will result in a "Press ENTER" prompt
+ feed("u")
+ expect(default_text:gsub("lines", "linesxy"))
+ feed("u")
+ expect(default_text:gsub("lines", "linesx"))
+ feed("u")
+ expect(default_text)
+ feed("u")
+
+ if case == "split" then
+ screen:expect([[
+ Inc substitution on |
+ two line^s |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ else
+ screen:expect([[
+ Inc substitution on |
+ two line^s |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ end
+
+ feed(":%s/tw/MO/g<enter>")
+ feed(":%s/MO/GO/g<enter>")
+ feed(":%s/GO/NO/g<enter>")
+ feed(":%s/NO/LO/g<enter>")
+ feed("u")
+ expect(default_text:gsub("tw", "NO"))
+ feed("u")
+ expect(default_text:gsub("tw", "GO"))
+ feed("u")
+ expect(default_text:gsub("tw", "MO"))
+ feed("u")
+
+ if case == "split" then
+ screen:expect([[
+ Inc substitution on |
+ ^MOo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ else
+ screen:expect([[
+ Inc substitution on |
+ ^MOo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ end
+ screen:detach()
+ end
+ end)
+
+ it('with undolevels=-1', function()
+ local screen = Screen.new(20,10)
+
+ for _, case in pairs(cases) do
+ clear()
+ common_setup(screen, case, default_text)
+
+ execute("set undolevels=-1")
+ feed(":%s/tw/MO/g<enter>")
+ -- using execute("undo") here will result in a "Press ENTER" prompt
+ feed("u")
+ if case == "split" then
+ screen:expect([[
+ Inc substitution on |
+ ^MOo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ else
+ screen:expect([[
+ Inc substitution on |
+ ^MOo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ end
+
+ -- repeat with an interrupted substitution
+ clear()
+ common_setup(screen, case, default_text)
+
+ execute("set undolevels=-1")
+ feed("1G")
+ feed("IL<esc>")
+ feed(":%s/tw/MO/g<esc>")
+ feed("u")
+
+ screen:expect([[
+ ^LInc substitution on|
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ Already...st change |
+ ]])
+ end
+ screen:detach()
+ end)
+
+end)
+
+describe(":substitute, inccommand=split", function()
+ if helpers.pending_win32(pending) then return end
+
+ local screen = Screen.new(30,15)
+
+ before_each(function()
+ clear()
+ common_setup(screen, "split", default_text .. default_text)
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it("preserves 'modified' buffer flag", function()
+ execute("set nomodified")
+ feed(":%s/tw")
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {11:[No Name] }|
+ |2| two lines |
+ |4| two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw^ |
+ ]])
+ feed([[<C-\><C-N>]]) -- Cancel the :substitute command.
+ eq(0, eval("&modified"))
+ end)
+
+ it('shows split window when typing the pattern', function()
+ feed(":%s/tw")
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {11:[No Name] [+] }|
+ |2| two lines |
+ |4| two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw^ |
+ ]])
+ end)
+
+ it('shows preview with empty replacement', function()
+ feed(":%s/tw/")
+ screen:expect([[
+ Inc substitution on |
+ o lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {11:[No Name] [+] }|
+ |2| o lines |
+ |4| o lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw/^ |
+ ]])
+
+ feed("x")
+ screen:expect([[
+ Inc substitution on |
+ xo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {11:[No Name] [+] }|
+ |2| {12:x}o lines |
+ |4| {12:x}o lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw/x^ |
+ ]])
+
+ feed("<bs>")
+ screen:expect([[
+ Inc substitution on |
+ o lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {11:[No Name] [+] }|
+ |2| o lines |
+ |4| o lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw/^ |
+ ]])
+
+ end)
+
+ it('shows split window when typing replacement', function()
+ feed(":%s/tw/XX")
+ screen:expect([[
+ Inc substitution on |
+ XXo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {11:[No Name] [+] }|
+ |2| {12:XX}o lines |
+ |4| {12:XX}o lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw/XX^ |
+ ]])
+ end)
+
+ it('does not show split window for :s/', function()
+ feed("2gg")
+ feed(":s/tw")
+ wait()
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :s/tw^ |
+ ]])
+ end)
+
+ it("'hlsearch' is active, 'cursorline' is not", function()
+ execute("set hlsearch cursorline")
+ feed("gg")
+
+ -- Assert that 'cursorline' is active.
+ screen:expect([[
+ {16:^Inc substitution on }|
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :set hlsearch cursorline |
+ ]])
+
+ feed(":%s/tw")
+ -- 'cursorline' is NOT active during preview.
+ screen:expect([[
+ Inc substitution on |
+ {9:tw}o lines |
+ Inc substitution on |
+ {9:tw}o lines |
+ |
+ {11:[No Name] [+] }|
+ |2| {9:tw}o lines |
+ |4| {9:tw}o lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw^ |
+ ]])
+ end)
+
+ it('highlights the replacement text', function()
+ feed('ggO')
+ feed('M M M<esc>')
+ feed(':%s/M/123/g')
+ screen:expect([[
+ 123 123 123 |
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ {11:[No Name] [+] }|
+ |1| {12:123} {12:123} {12:123} |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/M/123/g^ |
+ ]])
+ end)
+
+ it('actually replaces text', function()
+ feed(":%s/tw/XX/g<Enter>")
+
+ screen:expect([[
+ Inc substitution on |
+ XXo lines |
+ Inc substitution on |
+ ^XXo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%s/tw/XX/g |
+ ]])
+ end)
+
+ it('shows correct line numbers with many lines', function()
+ feed("gg")
+ feed("2yy")
+ feed("2000p")
+ execute("1,1000s/tw/BB/g")
+
+ feed(":%s/tw/X")
+ screen:expect([[
+ BBo lines |
+ Inc substitution on |
+ Xo lines |
+ Inc substitution on |
+ Xo lines |
+ {11:[No Name] [+] }|
+ |1001| {12:X}o lines |
+ |1003| {12:X}o lines |
+ |1005| {12:X}o lines |
+ |1007| {12:X}o lines |
+ |1009| {12:X}o lines |
+ |1011| {12:X}o lines |
+ |1013| {12:X}o lines |
+ {10:[Preview] }|
+ :%s/tw/X^ |
+ ]])
+ end)
+
+ it('does not spam the buffer numbers', function()
+ -- The preview buffer is re-used (unless user deleted it), so buffer numbers
+ -- will not increase on each keystroke.
+ feed(":%s/tw/Xo/g")
+ -- Delete and re-type the g a few times.
+ feed("<BS>")
+ wait()
+ feed("g")
+ wait()
+ feed("<BS>")
+ wait()
+ feed("g")
+ wait()
+ feed("<CR>")
+ wait()
+ feed(":vs tmp<enter>")
+ eq(3, helpers.call('bufnr', '$'))
+ end)
+
+ it('works with the n flag', function()
+ feed(":%s/tw/Mix/n<Enter>")
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ ^ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ 2 matches on 2 lines |
+ ]])
+ end)
+
+ it("deactivates if 'redrawtime' is exceeded #5602", function()
+ -- Assert that 'inccommand' is ENABLED initially.
+ eq("split", eval("&inccommand"))
+ -- Set 'redrawtime' to minimal value, to ensure timeout is triggered.
+ execute("set redrawtime=1 nowrap")
+ -- Load a big file.
+ execute("silent edit! test/functional/fixtures/bigfile.txt")
+ -- Start :substitute with a slow pattern.
+ feed([[:%s/B.*N/x]])
+ wait()
+
+ -- Assert that 'inccommand' is DISABLED in cmdline mode.
+ eq("", eval("&inccommand"))
+ -- Assert that preview cleared (or never manifested).
+ screen:expect([[
+ 0000;<control>;Cc;0;BN;;;;;N;N|
+ 0001;<control>;Cc;0;BN;;;;;N;S|
+ 0002;<control>;Cc;0;BN;;;;;N;S|
+ 0003;<control>;Cc;0;BN;;;;;N;E|
+ 0004;<control>;Cc;0;BN;;;;;N;E|
+ 0005;<control>;Cc;0;BN;;;;;N;E|
+ 0006;<control>;Cc;0;BN;;;;;N;A|
+ 0007;<control>;Cc;0;BN;;;;;N;B|
+ 0008;<control>;Cc;0;BN;;;;;N;B|
+ 0009;<control>;Cc;0;S;;;;;N;CH|
+ 000A;<control>;Cc;0;B;;;;;N;LI|
+ 000B;<control>;Cc;0;S;;;;;N;LI|
+ 000C;<control>;Cc;0;WS;;;;;N;F|
+ 000D;<control>;Cc;0;B;;;;;N;CA|
+ :%s/B.*N/x^ |
+ ]])
+
+ -- Assert that 'inccommand' is again ENABLED after leaving cmdline mode.
+ feed([[<C-\><C-N>]])
+ eq("split", eval("&inccommand"))
+ end)
+
+ it("clears preview if non-previewable command is edited #5585", function()
+ -- Put a non-previewable command in history.
+ execute("echo 'foo'")
+ -- Start an incomplete :substitute command.
+ feed(":1,2s/t/X")
+
+ screen:expect([[
+ Inc subsXitution on |
+ Xwo lines |
+ Inc substitution on |
+ two lines |
+ |
+ {11:[No Name] [+] }|
+ |1| Inc subs{12:X}itution on |
+ |2| {12:X}wo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :1,2s/t/X^ |
+ ]])
+
+ -- Select the previous command.
+ feed("<C-P>")
+ -- Assert that preview was cleared.
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :echo 'foo'^ |
+ ]])
+ end)
+
+end)
+
+describe("inccommand=nosplit", function()
+ if helpers.pending_win32(pending) then return end
+
+ local screen = Screen.new(20,10)
+
+ before_each(function()
+ clear()
+ common_setup(screen, "nosplit", default_text .. default_text)
+ end)
+
+ after_each(function()
+ if screen then screen:detach() end
+ end)
+
+ it("works with :smagic, :snomagic", function()
+ execute("set hlsearch")
+ insert("Line *.3.* here")
+
+ feed(":%smagic/3.*/X") -- start :smagic command
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ Line *.X |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%smagic/3.*/X^ |
+ ]])
+
+
+ feed([[<C-\><C-N>]]) -- cancel
+ feed(":%snomagic/3.*/X") -- start :snomagic command
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ Line *.X here |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%snomagic/3.*/X^ |
+ ]])
+ end)
+
+ it('never shows preview buffer', function()
+ execute("set hlsearch")
+
+ feed(":%s/tw")
+ screen:expect([[
+ Inc substitution on |
+ {9:tw}o lines |
+ Inc substitution on |
+ {9:tw}o lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%s/tw^ |
+ ]])
+
+ feed("/BM")
+ screen:expect([[
+ Inc substitution on |
+ BMo lines |
+ Inc substitution on |
+ BMo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%s/tw/BM^ |
+ ]])
+
+ feed("/")
+ screen:expect([[
+ Inc substitution on |
+ BMo lines |
+ Inc substitution on |
+ BMo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%s/tw/BM/^ |
+ ]])
+
+ feed("<enter>")
+ screen:expect([[
+ Inc substitution on |
+ BMo lines |
+ Inc substitution on |
+ ^BMo lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%s/tw/BM/ |
+ ]])
+ end)
+
+ it("clears preview if non-previewable command is edited", function()
+ -- Put a non-previewable command in history.
+ execute("echo 'foo'")
+ -- Start an incomplete :substitute command.
+ feed(":1,2s/t/X")
+
+ screen:expect([[
+ Inc subsXitution on |
+ Xwo lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :1,2s/t/X^ |
+ ]])
+
+ -- Select the previous command.
+ feed("<C-P>")
+ -- Assert that preview was cleared.
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :echo 'foo'^ |
+ ]])
+ end)
+end)
+
+describe(":substitute, 'inccommand' with a failing expression", function()
+ if helpers.pending_win32(pending) then return end
+
+ local screen = Screen.new(20,10)
+ local cases = { "", "split", "nosplit" }
+
+ local function refresh(case)
+ clear()
+ common_setup(screen, case, default_text)
+ end
+
+ it('in the pattern does nothing', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ execute("set inccommand=" .. case)
+ feed(":silent! %s/tw\\(/LARD/<enter>")
+ expect(default_text)
+ end
+ end)
+
+ it('in the replacement deletes the matches', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ local replacements = { "\\='LARD", "\\=xx_novar__xx" }
+
+ for _, repl in pairs(replacements) do
+ execute("set inccommand=" .. case)
+ feed(":silent! %s/tw/" .. repl .. "/<enter>")
+ expect(default_text:gsub("tw", ""))
+ execute("undo")
+ end
+ end
+ end)
+
+ it('in the range does not error #5912', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ feed(':100s/')
+
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :100s/^ |
+ ]])
+
+ feed('<enter>')
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ ^ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {14:E16: Invalid range} |
+ ]])
+ end
+ end)
+
+end)
+
+describe("'inccommand' and :cnoremap", function()
+ local cases = { "", "split", "nosplit" }
+
+ local function refresh(case)
+ clear()
+ common_setup(nil, case, default_text)
+ end
+
+ it('work with remapped characters', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ local command = "%s/lines/LINES/g"
+
+ for i = 1, string.len(command) do
+ local c = string.sub(command, i, i)
+ execute("cnoremap ".. c .. " " .. c)
+ end
+
+ execute(command)
+ expect([[
+ Inc substitution on
+ two LINES
+ ]])
+ end
+ end)
+
+ it('work when mappings move the cursor', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ execute("cnoremap ,S LINES/<left><left><left><left><left><left>")
+
+ feed(":%s/lines/,Sor three <enter>")
+ expect([[
+ Inc substitution on
+ two or three LINES
+ ]])
+
+ execute("cnoremap ;S /X/<left><left><left>")
+ feed(":%s/;SI<enter>")
+ expect([[
+ Xnc substitution on
+ two or three LXNES
+ ]])
+
+ execute("cnoremap ,T //Y/<left><left><left>")
+ feed(":%s,TX<enter>")
+ expect([[
+ Ync substitution on
+ two or three LYNES
+ ]])
+
+ execute("cnoremap ;T s//Z/<left><left><left>")
+ feed(":%;TY<enter>")
+ expect([[
+ Znc substitution on
+ two or three LZNES
+ ]])
+ end
+ end)
+
+ it('does not work with a failing mapping', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ execute("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
+
+ feed(":%s/tw/tox<enter>")
+
+ -- error thrown b/c of the mapping
+ neq(nil, eval('v:errmsg'):find('^E523:'))
+ expect(default_text)
+ end
+ end)
+
+ it('work when temporarily moving the cursor', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ execute("cnoremap <expr> x cursor(1, 1)[-1].'x'")
+
+ feed(":%s/tw/tox/g<enter>")
+ expect(default_text:gsub("tw", "tox"))
+ end
+ end)
+
+ it("work when a mapping disables 'inccommand'", function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ execute("cnoremap <expr> x execute('set inccommand=')[-1]")
+
+ feed(":%s/tw/toxa/g<enter>")
+ expect(default_text:gsub("tw", "toa"))
+ end
+ end)
+
+ it('work with a complex mapping', function()
+ for _, case in pairs(cases) do
+ refresh(case)
+ source([[cnoremap x <C-\>eextend(g:, {'fo': getcmdline()})
+ \.fo<CR><C-c>:new<CR>:bw!<CR>:<C-r>=remove(g:, 'fo')<CR>x]])
+
+ feed(":%s/tw/tox")
+ feed("/<enter>")
+ expect(default_text:gsub("tw", "tox"))
+ end
+ end)
+
+end)
+
+describe("'inccommand' autocommands", function()
+ before_each(clear)
+
+ -- keys are events to be tested
+ -- values are arrays like
+ -- { open = { 1 }, close = { 2, 3} }
+ -- which would mean that during the test below the event fires for
+ -- buffer 1 when opening the preview window, and for buffers 2 and 3
+ -- when closing the preview window
+ local eventsExpected = {
+ BufAdd = {},
+ BufDelete = {},
+ BufEnter = {},
+ BufFilePost = {},
+ BufFilePre = {},
+ BufHidden = {},
+ BufLeave = {},
+ BufNew = {},
+ BufNewFile = {},
+ BufRead = {},
+ BufReadCmd = {},
+ BufReadPre = {},
+ BufUnload = {},
+ BufWinEnter = {},
+ BufWinLeave = {},
+ BufWipeout = {},
+ BufWrite = {},
+ BufWriteCmd = {},
+ BufWritePost = {},
+ Syntax = {},
+ FileType = {},
+ WinEnter = {},
+ WinLeave = {},
+ CmdwinEnter = {},
+ CmdwinLeave = {},
+ }
+
+ local function bufferlist(t)
+ local s = ""
+ for _, buffer in pairs(t) do
+ s = s .. ", " .. tostring(buffer)
+ end
+ return s
+ end
+
+ -- fill the table with default values
+ for event, _ in pairs(eventsExpected) do
+ eventsExpected[event].open = eventsExpected[event].open or {}
+ eventsExpected[event].close = eventsExpected[event].close or {}
+ end
+
+ local function register_autocmd(event)
+ meths.set_var(event .. "_fired", {})
+ execute("autocmd " .. event .. " * call add(g:" .. event .. "_fired, expand('<abuf>'))")
+ end
+
+ it('are not fired when splitting', function()
+ common_setup(nil, "split", default_text)
+
+ local eventsObserved = {}
+ for event, _ in pairs(eventsExpected) do
+ eventsObserved[event] = {}
+ register_autocmd(event)
+ end
+
+ feed(":%s/tw")
+
+ for event, _ in pairs(eventsExpected) do
+ eventsObserved[event].open = meths.get_var(event .. "_fired")
+ meths.set_var(event .. "_fired", {})
+ end
+
+ feed("/<enter>")
+
+ for event, _ in pairs(eventsExpected) do
+ eventsObserved[event].close = meths.get_var(event .. "_fired")
+ end
+
+ for event, _ in pairs(eventsExpected) do
+ eq(event .. bufferlist(eventsExpected[event].open),
+ event .. bufferlist(eventsObserved[event].open))
+ eq(event .. bufferlist(eventsExpected[event].close),
+ event .. bufferlist(eventsObserved[event].close))
+ end
+ end)
+
+end)
+
+describe("'inccommand' split windows", function()
+ if helpers.pending_win32(pending) then return end
+
+ local screen
+ local function refresh()
+ clear()
+ screen = Screen.new(40,30)
+ common_setup(screen, "split", default_text)
+ end
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it('work after more splits', function()
+ refresh()
+
+ feed("gg")
+ execute("vsplit")
+ execute("split")
+ feed(":%s/tw")
+ screen:expect([[
+ Inc substitution on {10:|}Inc substitution on|
+ two lines {10:|}two lines |
+ {10:|} |
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {11:[No Name] [+] }{10:|}{15:~ }|
+ Inc substitution on {10:|}{15:~ }|
+ two lines {10:|}{15:~ }|
+ {10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {10:[No Name] [+] [No Name] [+] }|
+ |2| two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw^ |
+ ]])
+
+ feed("<esc>")
+ execute("only")
+ execute("split")
+ execute("vsplit")
+
+ feed(":%s/tw")
+ screen:expect([[
+ Inc substitution on {10:|}Inc substitution on|
+ two lines {10:|}two lines |
+ {10:|} |
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {15:~ }{10:|}{15:~ }|
+ {11:[No Name] [+] }{10:[No Name] [+] }|
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {10:[No Name] [+] }|
+ |2| two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw^ |
+ ]])
+ end)
+
+ local settings = {
+ "splitbelow",
+ "splitright",
+ "noequalalways",
+ "equalalways eadirection=ver",
+ "equalalways eadirection=hor",
+ "equalalways eadirection=both",
+ }
+
+ it("are not affected by various settings", function()
+ for _, setting in pairs(settings) do
+ refresh()
+ execute("set " .. setting)
+
+ feed(":%s/tw")
+
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {11:[No Name] [+] }|
+ |2| two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :%s/tw^ |
+ ]])
+ end
+ end)
+
+end)
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index 6f5cadaf81..cec19250d2 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -1,9 +1,11 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim
local feed, next_message, eq = helpers.feed, helpers.next_message, helpers.eq
local expect = helpers.expect
local Screen = require('test.functional.ui.screen')
+if helpers.pending_win32(pending) then return end
+
describe('mappings', function()
local cid
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 993bbd5b0e..17d949825a 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1,42 +1,41 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths
local insert, execute = helpers.insert, helpers.execute
local eq, funcs = helpers.eq, helpers.funcs
+if helpers.pending_win32(pending) then return end
+
describe('Mouse input', function()
local screen
- local hlgroup_colors = {
- NonText = Screen.colors.Blue,
- Visual = Screen.colors.LightGrey
- }
-
before_each(function()
clear()
meths.set_option('mouse', 'a')
meths.set_option('listchars', 'eol:$')
- -- set mouset to very high value to ensure that even in valgrind/travis,
+ -- set mousetime to very high value to ensure that even in valgrind/travis,
-- nvim will still pick multiple clicks
- meths.set_option('mouset', 5000)
+ meths.set_option('mousetime', 5000)
screen = Screen.new(25, 5)
screen:attach()
screen:set_default_attr_ids({
- [1] = {background = hlgroup_colors.Visual},
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {background = Screen.colors.LightGrey},
[2] = {bold = true},
[3] = {
- foreground = hlgroup_colors.NonText,
- background = hlgroup_colors.Visual,
+ foreground = Screen.colors.Blue,
+ background = Screen.colors.LightGrey,
bold = true,
},
+ [4] = {reverse = true},
+ [5] = {bold = true, reverse = true},
})
- screen:set_default_attr_ignore( {{bold=true, foreground=hlgroup_colors.NonText}} )
feed('itesting<cr>mouse<cr>support and selection<esc>')
screen:expect([[
testing |
mouse |
support and selectio^n |
- ~ |
+ {0:~ }|
|
]])
end)
@@ -45,13 +44,13 @@ describe('Mouse input', function()
screen:detach()
end)
- it('left click moves cursor', function()
+ it('single left click moves cursor', function()
feed('<LeftMouse><2,1>')
screen:expect([[
testing |
mo^use |
support and selection |
- ~ |
+ {0:~ }|
|
]])
feed('<LeftMouse><0,0>')
@@ -59,17 +58,298 @@ describe('Mouse input', function()
^testing |
mouse |
support and selection |
- ~ |
+ {0:~ }|
|
]])
end)
+ it('double left click enters visual mode', function()
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ screen:expect([[
+ {1:testin}^g |
+ mouse |
+ support and selection |
+ {0:~ }|
+ {2:-- VISUAL --} |
+ ]])
+ end)
+
+ it('triple left click enters visual line mode', function()
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ screen:expect([[
+ ^t{1:esting}{3: } |
+ mouse |
+ support and selection |
+ {0:~ }|
+ {2:-- VISUAL LINE --} |
+ ]])
+ end)
+
+ it('quadruple left click enters visual block mode', function()
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ feed('<LeftMouse><0,0>')
+ feed('<LeftRelease><0,0>')
+ screen:expect([[
+ ^testing |
+ mouse |
+ support and selection |
+ {0:~ }|
+ {2:-- VISUAL BLOCK --} |
+ ]])
+ end)
+
+ describe('tab drag', function()
+ before_each(function()
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ tab = { background=Screen.colors.LightGrey, underline=true },
+ sel = { bold=true },
+ fill = { reverse=true }
+ })
+ screen.timeout = 15000
+ end)
+
+ it('in tabline on filler space moves tab to the end', function()
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftMouse><4,0>')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><14,0>')
+ screen:expect([[
+ {tab: + bar }{sel: + foo }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('in 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
+
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftMouse><11,0>')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><6,0>')
+ screen:expect([[
+ {sel: + bar }{tab: + foo }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('in tabline to the right moves tab right', function()
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftMouse><4,0>')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><7,0>')
+ screen:expect([[
+ {tab: + bar }{sel: + foo }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('out of tabline under filler space moves tab to the end', function()
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftMouse><4,0>')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><4,1>')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><14,1>')
+ screen:expect([[
+ {tab: + bar }{sel: + foo }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ 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
+
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftMouse><11,0>')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><11,1>')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><6,1>')
+ screen:expect([[
+ {sel: + bar }{tab: + foo }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('out of tabline to the right moves tab right', function()
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftMouse><4,0>')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><4,1>')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('<LeftDrag><7,1>')
+ screen:expect([[
+ {tab: + bar }{sel: + foo }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+ end)
+
describe('tabline', function()
- local tab_attrs = {
- tab = { background=Screen.colors.LightGrey, underline=true },
- sel = { bold=true },
- fill = { reverse=true }
- }
+ before_each(function()
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ tab = { background=Screen.colors.LightGrey, underline=true },
+ sel = { bold=true },
+ fill = { reverse=true }
+ })
+ end)
it('left click in default tabline (position 4) switches to tab', function()
execute('%delete')
@@ -79,18 +359,18 @@ describe('Mouse input', function()
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
feed('<LeftMouse><4,0>')
screen:expect([[
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
this is fo^o |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
end)
it('left click in default tabline (position 24) closes tab', function()
@@ -102,18 +382,18 @@ describe('Mouse input', function()
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
feed('<LeftMouse><24,0>')
screen:expect([[
this is fo^o |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
end)
it('double click in default tabline (position 4) opens new tab', function()
@@ -125,18 +405,18 @@ describe('Mouse input', function()
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
feed('<2-LeftMouse><4,0>')
screen:expect([[
{sel: Name] }{tab: + foo + bar }{fill: }{tab:X}|
^ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
end)
describe('%@ label', function()
@@ -158,9 +438,9 @@ describe('Mouse input', function()
{fill:test-test2 }|
mouse |
support and selectio^n |
- ~ |
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
meths.set_var('reply', {})
end)
@@ -216,7 +496,7 @@ describe('Mouse input', function()
testing |
mo^use |
support and selection |
- ~ |
+ {0:~ }|
|
]])
feed('<LeftDrag><4,1>')
@@ -224,7 +504,7 @@ describe('Mouse input', function()
testing |
mo{1:us}^e |
support and selection |
- ~ |
+ {0:~ }|
{2:-- VISUAL --} |
]])
feed('<LeftDrag><2,2>')
@@ -232,7 +512,7 @@ describe('Mouse input', function()
testing |
mo{1:use}{3: } |
{1:su}^pport and selection |
- ~ |
+ {0:~ }|
{2:-- VISUAL --} |
]])
feed('<LeftDrag><0,0>')
@@ -240,18 +520,19 @@ describe('Mouse input', function()
^t{1:esting}{3: } |
{1:mou}se |
support and selection |
- ~ |
+ {0:~ }|
{2:-- VISUAL --} |
]])
end)
it('left drag changes visual selection after tab click', function()
- local tab_attrs = {
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
tab = { background=Screen.colors.LightGrey, underline=true },
sel = { bold=true },
fill = { reverse=true },
vis = { background=Screen.colors.LightGrey }
- }
+ })
execute('silent file foo | tabnew | file bar')
insert('this is bar')
execute('tabprevious') -- go to first tab
@@ -259,27 +540,27 @@ describe('Mouse input', function()
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
mouse |
support and selectio^n |
- ~ |
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
feed('<LeftMouse><10,0><LeftRelease>') -- go to second tab
helpers.wait()
feed('<LeftMouse><0,1>')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
^this is bar |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
|
- ]], tab_attrs)
+ ]])
feed('<LeftDrag><4,1>')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
{vis:this}^ is bar |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
{sel:-- VISUAL --} |
- ]], tab_attrs)
+ ]])
end)
it('two clicks will select the word and enter VISUAL', function()
@@ -288,7 +569,7 @@ describe('Mouse input', function()
testing |
mouse |
{1:suppor}^t and selection |
- ~ |
+ {0:~ }|
{2:-- VISUAL --} |
]])
end)
@@ -299,7 +580,7 @@ describe('Mouse input', function()
testing |
mouse |
{1:su}^p{1:port and selection}{3: } |
- ~ |
+ {0:~ }|
{2:-- VISUAL LINE --} |
]])
end)
@@ -310,7 +591,7 @@ describe('Mouse input', function()
testing |
mouse |
su^pport and selection |
- ~ |
+ {0:~ }|
{2:-- VISUAL BLOCK --} |
]])
end)
@@ -321,7 +602,7 @@ describe('Mouse input', function()
^testing |
mouse |
support and selection |
- ~ |
+ {0:~ }|
|
]])
feed('<RightMouse><2,2>')
@@ -329,7 +610,7 @@ describe('Mouse input', function()
{1:testing}{3: } |
{1:mouse}{3: } |
{1:su}^pport and selection |
- ~ |
+ {0:~ }|
{2:-- VISUAL --} |
]])
end)
@@ -361,73 +642,71 @@ describe('Mouse input', function()
]])
screen:try_resize(53, 14)
execute('sp', 'vsp')
- screen:set_default_attr_ignore( {{bold=true, foreground=hlgroup_colors.NonText},
- {reverse=true}, {bold=true, reverse=true}} )
screen:expect([[
- lines |lines |
- to |to |
- test |test |
- mouse scrolling |mouse scrolling |
- ^ | |
- ~ |~ |
- [No Name] [+] [No Name] [+] |
+ lines {4:|}lines |
+ to {4:|}to |
+ test {4:|}test |
+ mouse scrolling {4:|}mouse scrolling |
+ ^ {4:|} |
+ {0:~ }{4:|}{0:~ }|
+ {5:[No Name] [+] }{4:[No Name] [+] }|
to |
test |
mouse scrolling |
|
- ~ |
- [No Name] [+] |
+ {0:~ }|
+ {4:[No Name] [+] }|
:vsp |
]])
feed('<MouseUp><0,0>')
screen:expect([[
- mouse scrolling |lines |
- ^ |to |
- ~ |test |
- ~ |mouse scrolling |
- ~ | |
- ~ |~ |
- [No Name] [+] [No Name] [+] |
+ mouse scrolling {4:|}lines |
+ ^ {4:|}to |
+ {0:~ }{4:|}test |
+ {0:~ }{4:|}mouse scrolling |
+ {0:~ }{4:|} |
+ {0:~ }{4:|}{0:~ }|
+ {5:[No Name] [+] }{4:[No Name] [+] }|
to |
test |
mouse scrolling |
|
- ~ |
- [No Name] [+] |
+ {0:~ }|
+ {4:[No Name] [+] }|
|
]])
feed('<MouseDown><27,0>')
screen:expect([[
- mouse scrolling |text |
- ^ |with |
- ~ |many |
- ~ |lines |
- ~ |to |
- ~ |test |
- [No Name] [+] [No Name] [+] |
+ mouse scrolling {4:|}text |
+ ^ {4:|}with |
+ {0:~ }{4:|}many |
+ {0:~ }{4:|}lines |
+ {0:~ }{4:|}to |
+ {0:~ }{4:|}test |
+ {5:[No Name] [+] }{4:[No Name] [+] }|
to |
test |
mouse scrolling |
|
- ~ |
- [No Name] [+] |
+ {0:~ }|
+ {4:[No Name] [+] }|
|
]])
feed('<MouseDown><27,7><MouseDown>')
screen:expect([[
- mouse scrolling |text |
- ^ |with |
- ~ |many |
- ~ |lines |
- ~ |to |
- ~ |test |
- [No Name] [+] [No Name] [+] |
+ mouse scrolling {4:|}text |
+ ^ {4:|}with |
+ {0:~ }{4:|}many |
+ {0:~ }{4:|}lines |
+ {0:~ }{4:|}to |
+ {0:~ }{4:|}test |
+ {5:[No Name] [+] }{4:[No Name] [+] }|
Inserting |
text |
with |
many |
lines |
- [No Name] [+] |
+ {4:[No Name] [+] }|
|
]])
end)
@@ -440,7 +719,7 @@ describe('Mouse input', function()
|
|
bbbbbbbbbbbbbbb^b |
- ~ |
+ {0:~ }|
|
]])
@@ -449,7 +728,7 @@ describe('Mouse input', function()
|
|
n bbbbbbbbbbbbbbbbbbb^b |
- ~ |
+ {0:~ }|
|
]])
@@ -458,8 +737,326 @@ describe('Mouse input', function()
g |
|
^t and selection bbbbbbbbb|
- ~ |
+ {0:~ }|
|
]])
end)
+
+ describe('on concealed text', function()
+ -- Helpful for reading the test expectations:
+ -- :match Error /\^/
+
+ before_each(function()
+ screen:try_resize(25, 7)
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
+ })
+ feed('ggdG')
+
+ execute('set concealcursor=n')
+ execute('set nowrap')
+ execute('syntax match NonText "\\<amet\\>" conceal')
+ execute('syntax match NonText "\\cs\\|g." conceal cchar=X')
+ execute('syntax match NonText "\\%(lo\\|cl\\)." conceal')
+ execute('syntax match NonText "Lo" conceal cchar=Y')
+
+ insert([[
+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr.
+ Stet clita kasd gubergren, no sea takimata sanctus est.
+ ]])
+
+ feed('gg')
+ end)
+
+ it('(level 1) click on non-wrapped lines', function()
+ execute('let &conceallevel=1', 'echo')
+
+ feed('<esc><LeftMouse><0,0>')
+ screen:expect([[
+ {c:^Y}rem ip{c:X}um do{c: } {c:X}it {c: }, con|
+ {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no|
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><1,0>')
+ screen:expect([[
+ {c:Y}^rem ip{c:X}um do{c: } {c:X}it {c: }, con|
+ {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no|
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,0>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do{c: } {c:^X}it {c: }, con|
+ {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no|
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,1>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: }, con|
+ {c:X}tet {c: }ta ka{c:X}d {c:X}^ber{c:X}en, no|
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end) -- level 1 - non wrapped
+
+ it('(level 1) click on wrapped lines', function()
+ execute('let &conceallevel=1', 'let &wrap=1', 'echo')
+
+ feed('<esc><LeftMouse><0,0>')
+ screen:expect([[
+ {c:^Y}rem ip{c:X}um do{c: } {c:X}it {c: } |
+ , con{c:X}etetur {c:X}adip{c:X}cin{c:X} |
+ elitr. |
+ {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en |
+ , no {c:X}ea takimata {c:X}anctu{c:X}|
+ e{c:X}t. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><6,1>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } |
+ , con{c:X}^etetur {c:X}adip{c:X}cin{c:X} |
+ elitr. |
+ {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en |
+ , no {c:X}ea takimata {c:X}anctu{c:X}|
+ e{c:X}t. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,1>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } |
+ , con{c:X}etetur {c:X}a^dip{c:X}cin{c:X} |
+ elitr. |
+ {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en |
+ , no {c:X}ea takimata {c:X}anctu{c:X}|
+ e{c:X}t. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,3>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } |
+ , con{c:X}etetur {c:X}adip{c:X}cin{c:X} |
+ elitr. |
+ {c:X}tet {c: }ta ka{c:X}d {c:X}^ber{c:X}en |
+ , no {c:X}ea takimata {c:X}anctu{c:X}|
+ e{c:X}t. |
+ |
+ ]])
+ end) -- level 1 - wrapped
+
+
+ it('(level 2) click on non-wrapped lines', function()
+ execute('let &conceallevel=2', 'echo')
+
+ feed('<esc><LeftMouse><0,0>')
+ screen:expect([[
+ {c:^Y}rem ip{c:X}um do {c:X}it , con{c:X}e|
+ {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no |
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><1,0>')
+ screen:expect([[
+ {c:Y}^rem ip{c:X}um do {c:X}it , con{c:X}e|
+ {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no |
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,0>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do {c:X}^it , con{c:X}e|
+ {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no |
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,1>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do {c:X}it , con{c:X}e|
+ {c:X}tet ta ka{c:X}d {c:X}b^er{c:X}en, no |
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end) -- level 2 - non wrapped
+
+ it('(level 2) click on wrapped lines', function()
+ execute('let &conceallevel=2', 'let &wrap=1', 'echo')
+
+ feed('<esc><LeftMouse><0,0>')
+ screen:expect([[
+ {c:^Y}rem ip{c:X}um do {c:X}it |
+ , con{c:X}etetur {c:X}adip{c:X}cin{c:X} |
+ elitr. |
+ {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en |
+ , no {c:X}ea takimata {c:X}anctu{c:X}|
+ e{c:X}t. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><6,1>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do {c:X}it |
+ , con{c:X}^etetur {c:X}adip{c:X}cin{c:X} |
+ elitr. |
+ {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en |
+ , no {c:X}ea takimata {c:X}anctu{c:X}|
+ e{c:X}t. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,1>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do {c:X}it |
+ , con{c:X}etetur {c:X}a^dip{c:X}cin{c:X} |
+ elitr. |
+ {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en |
+ , no {c:X}ea takimata {c:X}anctu{c:X}|
+ e{c:X}t. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,3>')
+ screen:expect([[
+ {c:Y}rem ip{c:X}um do {c:X}it |
+ , con{c:X}etetur {c:X}adip{c:X}cin{c:X} |
+ elitr. |
+ {c:X}tet ta ka{c:X}d {c:X}b^er{c:X}en |
+ , no {c:X}ea takimata {c:X}anctu{c:X}|
+ e{c:X}t. |
+ |
+ ]])
+ end) -- level 2 - wrapped
+
+
+ it('(level 3) click on non-wrapped lines', function()
+ execute('let &conceallevel=3', 'echo')
+
+ feed('<esc><LeftMouse><0,0>')
+ screen:expect([[
+ ^rem ipum do it , conetetu|
+ tet ta kad beren, no ea t|
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><1,0>')
+ screen:expect([[
+ r^em ipum do it , conetetu|
+ tet ta kad beren, no ea t|
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,0>')
+ screen:expect([[
+ rem ipum do it ^, conetetu|
+ tet ta kad beren, no ea t|
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,1>')
+ screen:expect([[
+ rem ipum do it , conetetu|
+ tet ta kad bere^n, no ea t|
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end) -- level 3 - non wrapped
+
+ it('(level 3) click on wrapped lines', function()
+ execute('let &conceallevel=3', 'let &wrap=1', 'echo')
+
+ feed('<esc><LeftMouse><0,0>')
+ screen:expect([[
+ ^rem ipum do it |
+ , conetetur adipcin |
+ elitr. |
+ tet ta kad beren |
+ , no ea takimata anctu |
+ et. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><6,1>')
+ screen:expect([[
+ rem ipum do it |
+ , cone^tetur adipcin |
+ elitr. |
+ tet ta kad beren |
+ , no ea takimata anctu |
+ et. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,1>')
+ screen:expect([[
+ rem ipum do it |
+ , conetetur adi^pcin |
+ elitr. |
+ tet ta kad beren |
+ , no ea takimata anctu |
+ et. |
+ |
+ ]])
+
+ feed('<esc><LeftMouse><15,3>')
+ screen:expect([[
+ rem ipum do it |
+ , conetetur adipcin |
+ elitr. |
+ tet ta kad bere^n |
+ , no ea takimata anctu |
+ et. |
+ |
+ ]])
+ end) -- level 3 - wrapped
+ end)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
new file mode 100644
index 0000000000..33086a61b1
--- /dev/null
+++ b/test/functional/ui/output_spec.lua
@@ -0,0 +1,68 @@
+local session = require('test.functional.helpers')(after_each)
+local child_session = require('test.functional.terminal.helpers')
+
+if session.pending_win32(pending) then return end
+
+describe("shell command :!", function()
+ local screen
+ before_each(function()
+ session.clear()
+ screen = child_session.screen_setup(0, '["'..session.nvim_prog..
+ '", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile"]')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
+ after_each(function()
+ child_session.feed_data("\3") -- Ctrl-C
+ screen:detach()
+ end)
+
+ it("displays output without LF/EOF. #4646 #4569 #3772", function()
+ -- NOTE: We use a child nvim (within a :term buffer)
+ -- to avoid triggering a UI flush.
+ child_session.feed_data(":!printf foo; sleep 200\n")
+ screen:expect([[
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ :!printf foo; sleep 200 |
+ |
+ foo |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
+ it("throttles shell-command output greater than ~10KB", function()
+ if os.getenv("TRAVIS") and session.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")
+
+ -- If we observe any line starting with a dot, then throttling occurred.
+ screen:expect("\n.", nil, nil, nil, true)
+
+ -- Final chunk of output should always be displayed, never skipped.
+ -- (Throttling is non-deterministic, this test is merely a sanity check.)
+ screen:expect([[
+ XXXXXXXXXX 2996 |
+ XXXXXXXXXX 2997 |
+ XXXXXXXXXX 2998 |
+ XXXXXXXXXX 2999 |
+ XXXXXXXXXX 3000 |
+ {10:Press ENTER or type command to continue}{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/quickfix_spec.lua b/test/functional/ui/quickfix_spec.lua
new file mode 100644
index 0000000000..29b28fe9f0
--- /dev/null
+++ b/test/functional/ui/quickfix_spec.lua
@@ -0,0 +1,196 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths
+local insert, execute = helpers.insert, helpers.execute
+
+
+describe('quickfix selection highlight', function()
+ local screen
+
+ before_each(function()
+ clear()
+
+ screen = Screen.new(25, 10)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = { bold = true, foreground = Screen.colors.Blue },
+ [2] = {reverse = true},
+ [3] = {foreground = Screen.colors.Brown},
+ [4] = {bold = true, reverse = true},
+ [5] = {background = Screen.colors.Green},
+ [6] = {foreground = Screen.colors.Brown, background = Screen.colors.Green},
+ [7] = {background = Screen.colors.Red},
+ [8] = {foreground = Screen.colors.Brown, background = Screen.colors.Red},
+ [9] = {background = Screen.colors.Fuchsia},
+ [10] = {foreground = Screen.colors.Red, background = Screen.colors.Fuchsia},
+ [11] = {foreground = Screen.colors.Red},
+ [12] = {foreground = Screen.colors.Brown, background = Screen.colors.Fuchsia},
+ })
+
+ meths.set_option('errorformat', '%m %l')
+ execute('syntax on')
+ execute('highlight Search guibg=Green')
+
+ insert([[
+ Line 1
+ Line 2
+ Line 3
+ Line 4
+ Line 5
+ ]])
+
+ execute('cad')
+ feed('gg')
+
+ screen:expect([[
+ ^Line 1 |
+ Line 2 |
+ Line 3 |
+ Line 4 |
+ Line 5 |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :cad |
+ ]])
+ end)
+
+ it('using default Search highlight group', function()
+ execute('copen')
+
+ screen:expect([[
+ Line 1 |
+ {2:[No Name] [+] }|
+ {5:^|}{6:1}{5:| Line }|
+ |{3:2}| Line |
+ |{3:3}| Line |
+ |{3:4}| Line |
+ |{3:5}| Line |
+ || |
+ {4:[Quickfix List] }|
+ :copen |
+ ]])
+
+ execute('cnext')
+
+ screen:expect([[
+ Line 1 |
+ {2:[No Name] [+] }|
+ |{3:1}| Line |
+ {5:^|}{6:2}{5:| Line }|
+ |{3:3}| Line |
+ |{3:4}| Line |
+ |{3:5}| Line |
+ || |
+ {4:[Quickfix List] }|
+ :cnext |
+ ]])
+ end)
+
+ it('using QuickFixLine highlight group', function()
+ execute('highlight QuickFixLine guibg=Red')
+
+ execute('copen')
+
+ screen:expect([[
+ Line 1 |
+ {2:[No Name] [+] }|
+ {7:^|}{8:1}{7:| Line }|
+ |{3:2}| Line |
+ |{3:3}| Line |
+ |{3:4}| Line |
+ |{3:5}| Line |
+ || |
+ {4:[Quickfix List] }|
+ :copen |
+ ]])
+
+ execute('cnext')
+
+ screen:expect([[
+ Line 1 |
+ {2:[No Name] [+] }|
+ |{3:1}| Line |
+ {7:^|}{8:2}{7:| Line }|
+ |{3:3}| Line |
+ |{3:4}| Line |
+ |{3:5}| Line |
+ || |
+ {4:[Quickfix List] }|
+ :cnext |
+ ]])
+ end)
+
+ it('combines with CursorLine', function()
+ execute('set cursorline')
+ execute('highlight QuickFixLine guifg=Red')
+ execute('highlight CursorLine guibg=Fuchsia')
+
+ execute('copen')
+
+ screen:expect([[
+ {9:Line 1 }|
+ {2:[No Name] [+] }|
+ {10:^|1| Line }|
+ |{3:2}| Line |
+ |{3:3}| Line |
+ |{3:4}| Line |
+ |{3:5}| Line |
+ || |
+ {4:[Quickfix List] }|
+ :copen |
+ ]])
+
+ feed('j')
+
+ screen:expect([[
+ {9:Line 1 }|
+ {2:[No Name] [+] }|
+ {11:|1| Line }|
+ {9:^|}{12:2}{9:| Line }|
+ |{3:3}| Line |
+ |{3:4}| Line |
+ |{3:5}| Line |
+ || |
+ {4:[Quickfix List] }|
+ :copen |
+ ]])
+ end)
+
+ it('QuickFixLine background takes precedence over CursorLine', function()
+ execute('set cursorline')
+ execute('highlight QuickFixLine guibg=Red')
+ execute('highlight CursorLine guibg=Fuchsia')
+
+ execute('copen')
+
+ screen:expect([[
+ {9:Line 1 }|
+ {2:[No Name] [+] }|
+ {7:^|}{8:1}{7:| Line }|
+ |{3:2}| Line |
+ |{3:3}| Line |
+ |{3:4}| Line |
+ |{3:5}| Line |
+ || |
+ {4:[Quickfix List] }|
+ :copen |
+ ]])
+
+ feed('j')
+
+ screen:expect([[
+ {9:Line 1 }|
+ {2:[No Name] [+] }|
+ {7:|}{8:1}{7:| Line }|
+ {9:^|}{12:2}{9:| Line }|
+ |{3:3}| Line |
+ |{3:4}| Line |
+ |{3:5}| Line |
+ || |
+ {4:[Quickfix List] }|
+ :copen |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 6372cbe081..54f43387dc 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -1,31 +1,17 @@
--- This module contains the Screen class, a complete Nvim screen implementation
--- designed for functional testing. The goal is to provide a simple and
--- intuitive API for verifying screen state after a set of actions.
+-- This module contains the Screen class, a complete Nvim UI implementation
+-- designed for functional testing (verifying screen state, in particular).
--
--- The screen class exposes a single assertion method, "Screen:expect". This
--- method takes a string representing the expected screen state and an optional
--- set of attribute identifiers for checking highlighted characters(more on
--- this later).
---
--- The string passed to "expect" will be processed according to these rules:
---
--- - Each line of the string represents and is matched individually against
--- a screen row.
--- - The entire string is stripped of common indentation
--- - Expected screen rows are stripped of the last character. The last
--- character should be used to write pipes(|) that make clear where the
--- screen ends
--- - The last line is stripped, so the string must have (row count + 1)
--- lines.
+-- Screen:expect() takes a string representing the expected screen state and an
+-- optional set of attribute identifiers for checking highlighted characters.
--
-- Example usage:
--
-- local screen = Screen.new(25, 10)
--- -- attach the screen to the current Nvim instance
+-- -- Attach the screen to the current Nvim instance.
-- screen:attach()
--- --enter insert mode and type some text
+-- -- Enter insert-mode and type some text.
-- feed('ihello screen')
--- -- declare an expectation for the eventual screen state
+-- -- Assert the expected screen state.
-- screen:expect([[
-- hello screen |
-- ~ |
@@ -39,31 +25,19 @@
-- -- INSERT -- |
-- ]]) -- <- Last line is stripped
--
--- Since screen updates are received asynchronously, "expect" is actually
--- specifying the eventual screen state. This is how "expect" works: It will
--- start the event loop with a timeout of 5 seconds. Each time it receives an
--- update the expected state will be checked against the updated state.
---
--- If the expected state matches the current state, the event loop will be
--- stopped and "expect" will return. If the timeout expires, the last match
--- error will be reported and the test will fail.
+-- Since screen updates are received asynchronously, expect() actually specifies
+-- the _eventual_ screen state.
--
--- If the second argument is passed to "expect", the screen rows will be
--- transformed before being matched against the string lines. The
--- transformation rule is simple: Each substring "S" composed with characters
--- having the exact same set of attributes will be substituted by "{K:S}",
--- where K is a key associated the attribute set via the second argument of
--- "expect".
--- If a transformation table is present, unexpected attribute sets in the final
--- state is considered an error. To make testing simpler, a list of attribute
--- sets that should be ignored can be passed as a third argument. Alternatively,
--- this third argument can be "true" to indicate that all unexpected attribute
--- sets should be ignored.
+-- This is how expect() works:
+-- * It starts the event loop with a timeout.
+-- * Each time it receives an update it checks that against the expected state.
+-- * If the expected state matches the current state, the event loop will be
+-- stopped and expect() will return.
+-- * If the timeout expires, the last match error will be reported and the
+-- test will fail.
--
--- To illustrate how this works, let's say that in the above example we wanted
--- to assert that the "-- INSERT --" string is highlighted with the bold
--- attribute(which normally is), here's how the call to "expect" should look
--- like:
+-- Continuing the above example, say we want to assert that "-- INSERT --" is
+-- highlighted with the bold attribute. The expect() call should look like this:
--
-- NonText = Screen.colors.Blue
-- screen:expect([[
@@ -81,32 +55,24 @@
--
-- In this case "b" is a string associated with the set composed of one
-- attribute: bold. Note that since the {b:} markup is not a real part of the
--- screen, the delimiter(|) had to be moved right. Also, the highlighting of the
--- NonText markers (~) is ignored in this test.
+-- screen, the delimiter "|" moved to the right. Also, the highlighting of the
+-- NonText markers "~" is ignored in this test.
+--
+-- Tests will often share a group of attribute sets to expect(). Those can be
+-- defined at the beginning of a test:
--
--- Multiple expect:s will likely share a group of attribute sets to test.
--- Therefore these could be specified at the beginning of a test like this:
-- NonText = Screen.colors.Blue
-- screen:set_default_attr_ids( {
-- [1] = {reverse = true, bold = true},
-- [2] = {reverse = true}
-- })
-- screen:set_default_attr_ignore( {{}, {bold=true, foreground=NonText}} )
--- These can be overridden for a specific expect expression, by passing
--- different sets as parameters.
--
--- To help writing screen tests, there is a utility function
--- "screen:snapshot_util()", that can be placed in a test file at any point an
--- "expect(...)" should be. It will wait a short amount of time and then dump
--- the current state of the screen, in the form of an "expect(..)" expression
--- that would match it exactly. "snapshot_util" optionally also take the
--- transformation and ignore set as parameters, like expect, or uses the default
--- set. It will generate a larger attribute transformation set, if needed.
--- To generate a text-only test without highlight checks,
--- use `screen:snapshot_util({},true)`
-
-local helpers = require('test.functional.helpers')
-local request, run = helpers.request, helpers.run
+-- To help write screen tests, see Screen:snapshot_util().
+-- To debug screen tests, see Screen:redraw_debug().
+
+local helpers = require('test.functional.helpers')(nil)
+local request, run, uimeths = helpers.request, helpers.run, helpers.uimeths
local dedent = helpers.dedent
local Screen = {}
@@ -126,7 +92,7 @@ end
do
local spawn, nvim_prog = helpers.spawn, helpers.nvim_prog
local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', '--embed'})
- local status, rv = session:request('vim_get_color_map')
+ local status, rv = session:request('nvim_get_color_map')
if not status then
print('failed to get color map')
os.exit(1)
@@ -170,9 +136,9 @@ function Screen.new(width, height)
update_menu = false,
visual_bell = false,
suspended = false,
+ mode = 'normal',
_default_attr_ids = nil,
_default_attr_ignore = nil,
- _mode = 'normal',
_mouse_enabled = true,
_attrs = {},
_cursor = {
@@ -192,22 +158,39 @@ function Screen:set_default_attr_ignore(attr_ignore)
self._default_attr_ignore = attr_ignore
end
-function Screen:attach(rgb)
- if rgb == nil then
- rgb = true
+function Screen:attach(options)
+ if options == nil then
+ options = {rgb=true}
end
- request('ui_attach', self._width, self._height, rgb)
+ uimeths.attach(self._width, self._height, options)
end
function Screen:detach()
- request('ui_detach')
+ uimeths.detach()
end
function Screen:try_resize(columns, rows)
- request('ui_try_resize', columns, rows)
+ uimeths.try_resize(columns, rows)
+ -- Give ourselves a chance to _handle_resize, which requires using
+ -- self.sleep() (for the resize notification) rather than run()
+ self:sleep(0.1)
end
-function Screen:expect(expected, attr_ids, attr_ignore)
+-- Asserts that `expected` eventually matches the screen state.
+--
+-- expected: Expected screen state (string). Each line represents a screen
+-- row. Last character of each row (typically "|") is stripped.
+-- Common indentation is stripped.
+-- 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)
-- remove the last line and dedent
expected = dedent(expected:gsub('\n[ ]+$', ''))
local expected_rows = {}
@@ -216,26 +199,52 @@ function Screen:expect(expected, attr_ids, attr_ignore)
row = row:sub(1, #row - 1)
table.insert(expected_rows, row)
end
+ if not any then
+ assert(self._height == #expected_rows,
+ "Expected screen state's row count(" .. #expected_rows
+ .. ') differs from configured height(' .. self._height .. ') of Screen.')
+ end
local ids = attr_ids or self._default_attr_ids
local ignore = attr_ignore or self._default_attr_ignore
self:wait(function()
+ if condition ~= nil then
+ local status, res = pcall(condition)
+ if not status then
+ return tostring(res)
+ end
+ end
local actual_rows = {}
for i = 1, self._height do
actual_rows[i] = self:_row_repr(self._rows[i], ids, ignore)
end
- for i = 1, self._height do
- if expected_rows[i] ~= actual_rows[i] then
- local msg_expected_rows = {}
- for j = 1, #expected_rows do
- msg_expected_rows[j] = expected_rows[j]
- end
- msg_expected_rows[i] = '*' .. msg_expected_rows[i]
- actual_rows[i] = '*' .. actual_rows[i]
+
+ if any then
+ -- Search for `expected` anywhere in the screen lines.
+ local actual_screen_str = table.concat(actual_rows, '\n')
+ if nil == string.find(actual_screen_str, expected) then
return (
- 'Row ' .. tostring(i) .. ' didn\'t match.\n'
- .. 'Expected:\n|' .. table.concat(msg_expected_rows, '|\n|') .. '|\n'
- .. 'Actual:\n|' .. table.concat(actual_rows, '|\n|') .. '|'
- )
+ 'Failed to match any screen lines.\n'
+ .. 'Expected (anywhere): "' .. expected .. '"\n'
+ .. 'Actual:\n |' .. table.concat(actual_rows, '|\n |') .. '|\n\n')
+ end
+ else
+ -- `expected` must match the screen lines exactly.
+ for i = 1, self._height do
+ if expected_rows[i] ~= actual_rows[i] then
+ local msg_expected_rows = {}
+ for j = 1, #expected_rows do
+ msg_expected_rows[j] = expected_rows[j]
+ end
+ msg_expected_rows[i] = '*' .. msg_expected_rows[i]
+ actual_rows[i] = '*' .. actual_rows[i]
+ return (
+ 'Row ' .. tostring(i) .. ' did not match.\n'
+ ..'Expected:\n |'..table.concat(msg_expected_rows, '|\n |')..'|\n'
+ ..'Actual:\n |'..table.concat(actual_rows, '|\n |')..'|\n\n'..[[
+To print the expect() call that would assert the current screen state, use
+screen:snaphot_util(). In case of non-deterministic failures, use
+screen:redraw_debug() to show all intermediate screen states. ]])
+ end
end
end
end)
@@ -290,6 +299,10 @@ If everything else fails, use Screen:redraw_debug to help investigate what is
end
end
+function Screen:sleep(ms)
+ pcall(function() self:wait(function() return "error" end, ms) end)
+end
+
function Screen:_redraw(updates)
for _, update in ipairs(updates) do
-- print('--')
@@ -297,12 +310,20 @@ function Screen:_redraw(updates)
local method = update[1]
for i = 2, #update do
local handler = self['_handle_'..method]
- handler(self, unpack(update[i]))
+ if handler ~= nil then
+ handler(self, unpack(update[i]))
+ else
+ self._on_event(method, update[i])
+ end
end
-- print(self:_current_screen())
end
end
+function Screen:set_on_event_handler(callback)
+ self._on_event = callback
+end
+
function Screen:_handle_resize(width, height)
local rows = {}
for _ = 1, height do
@@ -354,8 +375,9 @@ function Screen:_handle_mouse_off()
end
function Screen:_handle_mode_change(mode)
- assert(mode == 'insert' or mode == 'replace' or mode == 'normal')
- self._mode = mode
+ assert(mode == 'insert' or mode == 'replace'
+ or mode == 'normal' or mode == 'cmdline')
+ self.mode = mode
end
function Screen:_handle_set_scroll_region(top, bot, left, right)
@@ -499,9 +521,13 @@ function Screen:_current_screen()
return table.concat(rv, '\n')
end
+-- Generates tests. Call it where Screen:expect() would be. Waits briefly, then
+-- dumps the current screen state in the form of Screen:expect().
+-- Use snapshot_util({},true) to generate a text-only (no attributes) test.
+--
+-- @see Screen:redraw_debug()
function Screen:snapshot_util(attrs, ignore)
- -- util to generate screen test
- pcall(function() self:wait(function() return "error" end, 250) end)
+ self:sleep(250)
self:print_snapshot(attrs, ignore)
end
@@ -529,7 +555,7 @@ function Screen:print_snapshot(attrs, ignore)
if attrs == nil then
attrs = {}
if self._default_attr_ids ~= nil then
- for i, a in ipairs(self._default_attr_ids) do
+ for i, a in pairs(self._default_attr_ids) do
attrs[i] = a
end
end
@@ -587,7 +613,7 @@ function Screen:_pprint_attrs(attrs)
return table.concat(items, ", ")
end
-function backward_find_meaningful(tbl, from) -- luacheck: ignore
+local function backward_find_meaningful(tbl, from) -- luacheck: no unused
for i = from or #tbl, 1, -1 do
if tbl[i] ~= ' ' then
return i + 1
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index a4545eeff0..0824585717 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -1,8 +1,10 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local spawn, set_session, clear = helpers.spawn, helpers.set_session, helpers.clear
local feed, execute = helpers.feed, helpers.execute
local insert = helpers.insert
+local eq = helpers.eq
+local eval = helpers.eval
describe('Initial screen', function()
local screen
@@ -15,7 +17,10 @@ describe('Initial screen', function()
set_session(screen_nvim)
screen = Screen.new()
screen:attach()
- screen:set_default_attr_ignore( {{bold=true, foreground=255}} )
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=255},
+ [1] = {bold=true, reverse=true},
+ } )
end)
after_each(function()
@@ -25,18 +30,18 @@ describe('Initial screen', function()
it('is the default initial screen', function()
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- [No Name] |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:[No Name] }|
|
]])
end)
@@ -49,7 +54,16 @@ describe('Screen', function()
clear()
screen = Screen.new()
screen:attach()
- screen:set_default_attr_ignore( {{bold=true, foreground=255}} )
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=255},
+ [1] = {bold=true, reverse=true},
+ [2] = {bold=true},
+ [3] = {reverse=true},
+ [4] = {background = Screen.colors.LightGrey, underline = true},
+ [5] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Fuchsia},
+ [6] = {bold = true, foreground = Screen.colors.Fuchsia},
+ [7] = {bold = true, foreground = Screen.colors.SeaGreen},
+ } )
end)
after_each(function()
@@ -147,18 +161,18 @@ describe('Screen', function()
execute('sp')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- [No Name] |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:[No Name] }|
|
- ~ |
- ~ |
- ~ |
- ~ |
- [No Name] |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] }|
:sp |
]])
end)
@@ -168,18 +182,18 @@ describe('Screen', function()
execute('resize 8')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- [No Name] |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:[No Name] }|
|
- ~ |
- ~ |
- [No Name] |
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] }|
:resize 8 |
]])
end)
@@ -187,36 +201,36 @@ describe('Screen', function()
it('horizontal and vertical', function()
execute('sp', 'vsp', 'vsp')
screen:expect([[
- ^ | | |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- [No Name] [No Name] [No Name] |
+ ^ {3:|} {3:|} |
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {1:[No Name] }{3:[No Name] [No Name] }|
|
- ~ |
- ~ |
- ~ |
- ~ |
- [No Name] |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] }|
|
]])
insert('hello')
screen:expect([[
- hell^o |hello |hello |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- [No Name] [+] [No Name] [+] [No Name] [+] |
+ hell^o {3:|}hello {3:|}hello |
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
hello |
- ~ |
- ~ |
- ~ |
- ~ |
- [No Name] [+] |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] [+] }|
|
]])
end)
@@ -228,55 +242,55 @@ describe('Screen', function()
execute('sp', 'vsp', 'vsp')
insert('hello')
screen:expect([[
- hell^o |hello |hello |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- [No Name] [+] [No Name] [+] [No Name] [+] |
+ hell^o {3:|}hello {3:|}hello |
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
hello |
- ~ |
- ~ |
- ~ |
- ~ |
- [No Name] [+] |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] [+] }|
|
]])
execute('tabnew')
insert('hello2')
feed('h')
screen:expect([[
- 4+ [No Name] + [No Name] X|
+ {4: }{5:4}{4:+ [No Name] }{2: + [No Name] }{3: }{4:X}|
hell^o2 |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
|
]])
execute('tabprevious')
screen:expect([[
- 4+ [No Name] + [No Name] X|
- hell^o |hello |hello |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- ~ |~ |~ |
- [No Name] [+] [No Name] [+] [No Name] [+] |
+ {2: }{6:4}{2:+ [No Name] }{4: + [No Name] }{3: }{4:X}|
+ hell^o {3:|}hello {3:|}hello |
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {0:~ }{3:|}{0:~ }{3:|}{0:~ }|
+ {1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
hello |
- ~ |
- ~ |
- ~ |
- [No Name] [+] |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] [+] }|
|
]])
end)
@@ -289,17 +303,17 @@ describe('Screen', function()
line 1 |
line 2 |
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- -- INSERT -- |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
]])
end)
end)
@@ -314,17 +328,17 @@ describe('Screen', function()
screen:expect([[
0123^456 |
789 |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:set ruler 1,5 All |
]])
end)
@@ -335,18 +349,18 @@ describe('Screen', function()
feed(':ls')
screen:expect([[
|
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:ls^ |
]])
end)
@@ -354,20 +368,20 @@ describe('Screen', function()
it('execute command with multi-line output', function()
feed(':ls<cr>')
screen:expect([[
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:ls |
1 %a "[No Name]" line 1 |
- Press ENTER or type command to continue^ |
+ {7:Press ENTER or type command to continue}^ |
]])
feed('<cr>') -- skip the "Press ENTER..." state or tests will hang
end)
@@ -392,19 +406,19 @@ describe('Screen', function()
]])
execute('sp', 'vsp', 'vsp')
screen:expect([[
- and |and |and |
- clearing |clearing |clearing |
- in |in |in |
- split |split |split |
- windows |windows |windows |
- ^ | | |
- [No Name] [+] [No Name] [+] [No Name] [+] |
+ and {3:|}and {3:|}and |
+ clearing {3:|}clearing {3:|}clearing |
+ in {3:|}in {3:|}in |
+ split {3:|}split {3:|}split |
+ windows {3:|}windows {3:|}windows |
+ ^ {3:|} {3:|} |
+ {1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
clearing |
in |
split |
windows |
|
- [No Name] [+] |
+ {3:[No Name] [+] }|
|
]])
end)
@@ -412,121 +426,121 @@ describe('Screen', function()
it('only affects the current scroll region', function()
feed('6k')
screen:expect([[
- ^scrolling |and |and |
- and |clearing |clearing |
- clearing |in |in |
- in |split |split |
- split |windows |windows |
- windows | | |
- [No Name] [+] [No Name] [+] [No Name] [+] |
+ ^scrolling {3:|}and {3:|}and |
+ and {3:|}clearing {3:|}clearing |
+ clearing {3:|}in {3:|}in |
+ in {3:|}split {3:|}split |
+ split {3:|}windows {3:|}windows |
+ windows {3:|} {3:|} |
+ {1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
clearing |
in |
split |
windows |
|
- [No Name] [+] |
+ {3:[No Name] [+] }|
|
]])
feed('<c-w>l')
screen:expect([[
- scrolling |and |and |
- and |clearing |clearing |
- clearing |in |in |
- in |split |split |
- split |windows |windows |
- windows |^ | |
- [No Name] [+] [No Name] [+] <Name] [+] |
+ scrolling {3:|}and {3:|}and |
+ and {3:|}clearing {3:|}clearing |
+ clearing {3:|}in {3:|}in |
+ in {3:|}split {3:|}split |
+ split {3:|}windows {3:|}windows |
+ windows {3:|}^ {3:|} |
+ {3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
split |
windows |
|
- [No Name] [+] |
+ {3:[No Name] [+] }|
|
]])
feed('gg')
screen:expect([[
- scrolling |^Inserting |and |
- and |text |clearing |
- clearing |with |in |
- in |many |split |
- split |lines |windows |
- windows |to | |
- [No Name] [+] [No Name] [+] <Name] [+] |
+ scrolling {3:|}^Inserting {3:|}and |
+ and {3:|}text {3:|}clearing |
+ clearing {3:|}with {3:|}in |
+ in {3:|}many {3:|}split |
+ split {3:|}lines {3:|}windows |
+ windows {3:|}to {3:|} |
+ {3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
split |
windows |
|
- [No Name] [+] |
+ {3:[No Name] [+] }|
|
]])
feed('7j')
screen:expect([[
- scrolling |with |and |
- and |many |clearing |
- clearing |lines |in |
- in |to |split |
- split |test |windows |
- windows |^scrolling | |
- [No Name] [+] [No Name] [+] <Name] [+] |
+ scrolling {3:|}with {3:|}and |
+ and {3:|}many {3:|}clearing |
+ clearing {3:|}lines {3:|}in |
+ in {3:|}to {3:|}split |
+ split {3:|}test {3:|}windows |
+ windows {3:|}^scrolling {3:|} |
+ {3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
split |
windows |
|
- [No Name] [+] |
+ {3:[No Name] [+] }|
|
]])
feed('2j')
screen:expect([[
- scrolling |lines |and |
- and |to |clearing |
- clearing |test |in |
- in |scrolling |split |
- split |and |windows |
- windows |^clearing | |
- [No Name] [+] [No Name] [+] <Name] [+] |
+ scrolling {3:|}lines {3:|}and |
+ and {3:|}to {3:|}clearing |
+ clearing {3:|}test {3:|}in |
+ in {3:|}scrolling {3:|}split |
+ split {3:|}and {3:|}windows |
+ windows {3:|}^clearing {3:|} |
+ {3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
split |
windows |
|
- [No Name] [+] |
+ {3:[No Name] [+] }|
|
]])
feed('5k')
screen:expect([[
- scrolling |^lines |and |
- and |to |clearing |
- clearing |test |in |
- in |scrolling |split |
- split |and |windows |
- windows |clearing | |
- [No Name] [+] [No Name] [+] <Name] [+] |
+ scrolling {3:|}^lines {3:|}and |
+ and {3:|}to {3:|}clearing |
+ clearing {3:|}test {3:|}in |
+ in {3:|}scrolling {3:|}split |
+ split {3:|}and {3:|}windows |
+ windows {3:|}clearing {3:|} |
+ {3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
split |
windows |
|
- [No Name] [+] |
+ {3:[No Name] [+] }|
|
]])
feed('k')
screen:expect([[
- scrolling |^many |and |
- and |lines |clearing |
- clearing |to |in |
- in |test |split |
- split |scrolling |windows |
- windows |and | |
- [No Name] [+] [No Name] [+] <Name] [+] |
+ scrolling {3:|}^many {3:|}and |
+ and {3:|}lines {3:|}clearing |
+ clearing {3:|}to {3:|}in |
+ in {3:|}test {3:|}split |
+ split {3:|}scrolling {3:|}windows |
+ windows {3:|}and {3:|} |
+ {3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
split |
windows |
|
- [No Name] [+] |
+ {3:[No Name] [+] }|
|
]])
end)
@@ -541,18 +555,17 @@ describe('Screen', function()
it('rebuilds the whole screen', function()
screen:expect([[
resize^ |
- ~ |
- ~ |
- ~ |
- -- INSERT -- |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
]])
end)
- -- FIXME this has some race conditions that cause it to fail periodically
- pending('has minimum width/height values', function()
+ it('has minimum width/height values', function()
screen:try_resize(1, 1)
screen:expect([[
- -- INS^ERT --|
+ {2:-- INS^ERT --}|
|
]])
feed('<esc>:ls')
@@ -562,4 +575,125 @@ describe('Screen', function()
]])
end)
end)
+
+ describe('mode change', function()
+ before_each(function()
+ screen:try_resize(25, 5)
+ end)
+
+ it('works in normal mode', function()
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]],nil,nil,function ()
+ eq("normal", screen.mode)
+ end)
+ end)
+
+ it('works in insert mode', function()
+ feed('i')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
+ ]],nil,nil,function ()
+ eq("insert", screen.mode)
+ end)
+
+ feed('word<esc>')
+ screen:expect([[
+ wor^d |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]], nil, nil, function ()
+ eq("normal", screen.mode)
+ end)
+ end)
+
+ it('works in replace mode', function()
+ feed('R')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- REPLACE --} |
+ ]], nil, nil, function ()
+ eq("replace", screen.mode)
+ end)
+
+ feed('word<esc>')
+ screen:expect([[
+ wor^d |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]], nil, nil, function ()
+ eq("normal", screen.mode)
+ end)
+ end)
+
+ it('works in cmdline mode', function()
+ feed(':')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :^ |
+ ]],nil,nil,function ()
+ eq("cmdline", screen.mode)
+ end)
+
+ feed('<esc>/')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ /^ |
+ ]],nil,nil,function ()
+ eq("cmdline", screen.mode)
+ end)
+
+
+ feed('<esc>?')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ?^ |
+ ]],nil,nil,function ()
+ eq("cmdline", screen.mode)
+ end)
+
+ feed('<esc>')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]],nil,nil,function ()
+ eq("normal", screen.mode)
+ end)
+ end)
+ end)
+
+ it('nvim_ui_attach() handles very large width/height #2180', function()
+ screen:detach()
+ screen = Screen.new(999, 999)
+ screen:attach()
+ eq(999, eval('&lines'))
+ eq(999, eval('&columns'))
+ end)
end)
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index e4217abcfe..3914648e8f 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -1,28 +1,24 @@
-local helpers = require('test.functional.helpers')
+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 execute = helpers.execute
+if helpers.pending_win32(pending) then return end
+
describe('search highlighting', function()
local screen
local colors = Screen.colors
- local hl_colors = {
- NonText = colors.Blue,
- Search = colors.Yellow,
- Message = colors.Red,
- }
before_each(function()
clear()
screen = Screen.new(40, 7)
screen:attach()
- --ignore highligting of ~-lines
screen:set_default_attr_ids( {
- [1] = {background = hl_colors.Search},
- [2] = {reverse = true},
- [3] = {foreground = hl_colors.Message},
+ [1] = {bold=true, foreground=Screen.colors.Blue},
+ [2] = {background = colors.Yellow}, -- Search
+ [3] = {reverse = true},
+ [4] = {foreground = colors.Red}, -- Message
})
- screen:set_default_attr_ignore( {{bold=true, foreground=hl_colors.NonText}} )
end)
it('is disabled by ":set nohlsearch"', function()
@@ -32,10 +28,10 @@ describe('search highlighting', function()
screen:expect([[
some ^text |
more text |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/text |
]])
end)
@@ -51,35 +47,35 @@ describe('search highlighting', function()
-- 'hlsearch' is enabled by default. #2859
feed("gg/text<cr>")
screen:expect([[
- some {1:^text} |
- more {1:text}stuff |
- stupid{1:texttext}stuff |
- a {1:text} word |
+ some {2:^text} |
+ more {2:text}stuff |
+ stupid{2:texttext}stuff |
+ a {2:text} word |
|
- ~ |
+ {1:~ }|
/text |
]])
-- overlapping matches not allowed
feed("3nx")
screen:expect([[
- some {1:text} |
- more {1:text}stuff |
- stupid{1:text}^extstuff |
- a {1:text} word |
+ some {2:text} |
+ more {2:text}stuff |
+ stupid{2:text}^extstuff |
+ a {2:text} word |
|
- ~ |
+ {1:~ }|
/text |
]])
feed("ggn*") -- search for entire word
screen:expect([[
- some {1:text} |
+ some {2:text} |
more textstuff |
stupidtextextstuff |
- a {1:^text} word |
+ a {2:^text} word |
|
- ~ |
+ {1:~ }|
/\<text\> |
]])
@@ -90,7 +86,7 @@ describe('search highlighting', function()
stupidtextextstuff |
a ^text word |
|
- ~ |
+ {1:~ }|
:nohlsearch |
]])
end)
@@ -104,45 +100,45 @@ describe('search highlighting', function()
]])
feed("gg/li")
screen:expect([[
- the first {2:li}ne |
+ the first {3:li}ne |
in a little file |
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/li^ |
]])
feed("t")
screen:expect([[
the first line |
- in a {2:lit}tle file |
+ in a {3:lit}tle file |
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/lit^ |
]])
feed("<cr>")
screen:expect([[
the first line |
- in a {1:^lit}tle file |
+ in a {2:^lit}tle file |
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/lit |
]])
feed("/fir")
screen:expect([[
- the {2:fir}st line |
- in a {1:lit}tle file |
+ the {3:fir}st line |
+ in a {2:lit}tle file |
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/fir^ |
]])
@@ -150,11 +146,11 @@ describe('search highlighting', function()
feed("<esc>/ttle")
screen:expect([[
the first line |
- in a {1:li}{2:ttle} file |
+ in a {2:li}{3:ttle} file |
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/ttle^ |
]])
end)
@@ -168,12 +164,12 @@ describe('search highlighting', function()
feed("gg/mat/e")
screen:expect([[
- not the {2:mat}ch you're looking for |
+ not the {3:mat}ch you're looking for |
the match is here |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/mat/e^ |
]])
@@ -181,22 +177,22 @@ describe('search highlighting', function()
feed("<esc>2/mat/e")
screen:expect([[
not the match you're looking for |
- the {2:mat}ch is here |
- ~ |
- ~ |
- ~ |
- ~ |
+ the {3:mat}ch is here |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/mat/e^ |
]])
feed("<cr>")
screen:expect([[
- not the {1:mat}ch you're looking for |
- the {1:ma^t}ch is here |
- ~ |
- ~ |
- ~ |
- ~ |
+ not the {2:mat}ch you're looking for |
+ the {2:ma^t}ch is here |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
/mat/e |
]])
end)
@@ -207,28 +203,37 @@ describe('search highlighting', function()
feed('/line\\na<cr>')
screen:expect([[
|
- a repeated {1:^line} |
- {1:a} repeated {1:line} |
- {1:a} repeated {1:line} |
- {1:a} repeated line |
- ~ |
- {3:search hit BOTTOM, continuing at TOP} |
+ a repeated {2:^line} |
+ {2:a} repeated {2:line} |
+ {2:a} repeated {2:line} |
+ {2:a} repeated line |
+ {1:~ }|
+ {4:search hit BOTTOM, continuing at TOP} |
]])
-- it redraws rows above the changed one
feed('4Grb')
screen:expect([[
|
- a repeated {1:line} |
- {1:a} repeated line |
- ^b repeated {1:line} |
- {1:a} repeated line |
- ~ |
- {3:search hit BOTTOM, continuing at TOP} |
+ a repeated {2:line} |
+ {2:a} repeated line |
+ ^b repeated {2:line} |
+ {2:a} repeated line |
+ {1:~ }|
+ {4:search hit BOTTOM, continuing at TOP} |
]])
end)
it('works with matchadd and syntax', function()
+ screen:set_default_attr_ids( {
+ [1] = {bold=true, foreground=Screen.colors.Blue},
+ [2] = {background = colors.Yellow},
+ [3] = {reverse = true},
+ [4] = {foreground = colors.Red},
+ [5] = {bold = true, background = colors.Green},
+ [6] = {italic = true, background = colors.Magenta},
+ [7] = {bold = true, background = colors.Yellow},
+ } )
execute('set hlsearch')
insert([[
very special text
@@ -243,25 +248,23 @@ describe('search highlighting', function()
-- is used (and matches with lower priorities are not combined)
execute("/ial te")
screen:expect([[
- very {4:spec^ial}{1: te}{5:xt} |
+ very {5:spec^ial}{2: te}{6:xt} |
|
- ~ |
- ~ |
- ~ |
- ~ |
- {3:search hit BOTTOM, continuing at TOP} |
- ]], {[1] = {background = hl_colors.Search}, [2] = {reverse = true},
- [3] = {foreground = hl_colors.Message}, [4] = {bold = true, background =
- colors.Green}, [5] = {italic = true, background = colors.Magenta}})
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {4:search hit BOTTOM, continuing at TOP} |
+ ]])
execute("call clearmatches()")
screen:expect([[
- very spec{1:^ial te}xt |
+ very spec{2:^ial te}xt |
|
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
:call clearmatches() |
]])
@@ -269,16 +272,14 @@ describe('search highlighting', function()
-- nonconflicting attributes are combined
execute("syntax keyword MyGroup special")
screen:expect([[
- very {4:spec}{5:^ial}{1: te}xt |
+ very {5:spec}{7:^ial}{2: te}xt |
|
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
:syntax keyword MyGroup special |
- ]], {[1] = {background = hl_colors.Search}, [2] = {reverse = true},
- [3] = {foreground = hl_colors.Message}, [4] = {bold = true,
- background = colors.Green}, [5] = {bold = true, background = hl_colors.Search}})
+ ]])
end)
end)
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index c32a7b9381..d02fc83809 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -1,7 +1,9 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
+if helpers.pending_win32(pending) then return end
+
describe('Signs', function()
local screen
@@ -9,7 +11,11 @@ describe('Signs', function()
clear()
screen = Screen.new()
screen:attach()
- screen:set_default_attr_ignore( {{}, {bold=true, foreground=255}} )
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=255},
+ [1] = {background = Screen.colors.Yellow},
+ [2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Grey},
+ } )
end)
after_each(function()
@@ -25,19 +31,19 @@ describe('Signs', function()
execute('sign place 2 line=3 name=piet buffer=1')
execute('sign place 3 line=1 name=pietx buffer=1')
screen:expect([[
- >!a |
- b |
- >>c |
- ^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:>!}a |
+ {2: }b |
+ {1:>>}c |
+ {2: }^ |
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
:sign place 3 line=1 name=pietx buffer=1 |
]])
end)
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index 66ea779011..ee3e4fa32a 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -1,22 +1,26 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
local insert = helpers.insert
+if helpers.pending_win32(pending) then return end
+
describe('Screen', function()
- local screen
+ local screen
- before_each(function()
+ before_each(function()
clear()
screen = Screen.new(nil,10)
screen:attach()
- screen:set_default_attr_ignore( {{bold=true, foreground=255}} )
- screen:set_default_attr_ids( {{foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray}} )
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray}
+ } )
end)
-
+
after_each(function()
screen:detach()
- end)
+ end)
describe("match and conceal", function()
@@ -46,13 +50,13 @@ describe('Screen', function()
{1:∧} |
{1:∧} |
^ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
:syn match dAmpersand '[&][&]' conceal cchar=∧ |
]])
end)
- it('double characters and move the cursor one line up.', function()
+ it('double characters and move the cursor one line up.', function()
feed("k")
screen:expect([[
{1:∧} |
@@ -62,8 +66,8 @@ describe('Screen', function()
{1:∧} |
^&& |
|
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
:syn match dAmpersand '[&][&]' conceal cchar=∧ |
]])
end)
@@ -78,13 +82,13 @@ describe('Screen', function()
{1:∧} |
{1:∧} |
|
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
:syn match dAmpersand '[&][&]' conceal cchar=∧ |
]])
end)
- it('double characters and move the cursor to the second line in the file.', function()
+ it('double characters and move the cursor to the second line in the file.', function()
feed("ggj")
screen:expect([[
{1:∧} |
@@ -94,13 +98,13 @@ describe('Screen', function()
{1:∧} |
{1:∧} |
|
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
:syn match dAmpersand '[&][&]' conceal cchar=∧ |
]])
end)
- it('double characters and then move the cursor to the beginning of the file and back to the end of the file.', function()
+ it('double characters and then move the cursor to the beginning of the file and back to the end of the file.', function()
feed("ggG")
screen:expect([[
{1:∧} |
@@ -110,13 +114,13 @@ describe('Screen', function()
{1:∧} |
{1:∧} |
^ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
:syn match dAmpersand '[&][&]' conceal cchar=∧ |
]])
end)
- end) -- multiple
-
+ end) -- multiple
+
it("keyword instances in initially in the document.", function()
feed("2ilambda<cr><ESC>")
execute("let &conceallevel=1")
@@ -125,36 +129,36 @@ describe('Screen', function()
{1:λ} |
{1:λ} |
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:syn keyword kLambda lambda conceal cchar=λ |
]])
end) -- Keyword
describe("regions in the document", function()
- before_each(function()
+ before_each(function()
feed("2")
insert("<r> a region of text </r>\n")
execute("let &conceallevel=1")
end)
-
- it('initially and conceal it.', function()
+
+ it('initially and conceal it.', function()
execute("syn region rText start='<r>' end='</r>' conceal cchar=R")
screen:expect([[
{1:R} |
{1:R} |
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
|
]])
end)
@@ -167,18 +171,18 @@ describe('Screen', function()
{1: } a region of text {1:-} |
{1: } a region of text {1:-} |
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
|
]])
end)
-
+
it('that are nested and conceal the nested region\'s start and end tags.', function()
- execute("syn region rText contains=rText matchgroup=rMatch start='<r>' end='</r>' concealends cchar=-")
+ execute("syn region rText contains=rText matchgroup=rMatch start='<r>' end='</r>' concealends cchar=-")
insert("<r> A region with <r> a nested <r> nested region.</r> </r> </r>\n")
screen:expect([[
{1: } a region of text {1:-} |
@@ -186,18 +190,18 @@ describe('Screen', function()
{1: } A region with {1: } a nested {1: } nested region.{1:-} |
{1:-} {1:-} |
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
|
]])
end)
end) -- regions in the document
describe("a region of text", function()
- before_each(function()
- execute("syntax conceal on")
+ before_each(function()
+ execute("syntax conceal on")
feed("2")
insert("<r> a region of text </r>\n")
execute("syn region rText start='<r>' end='</r>' cchar=-")
@@ -208,12 +212,12 @@ describe('Screen', function()
{1:-} |
{1:-} |
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:syn region rText start='<r>' end='</r>' cchar=- |
]])
end)
@@ -229,10 +233,10 @@ describe('Screen', function()
<i> italian text </i> |
<i> italian text </i> |
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:syn region iText start='<i>' end='</i>' cchar=* |
]])
execute("syntax conceal on")
@@ -243,27 +247,27 @@ describe('Screen', function()
{1:*} |
{1:*} |
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:syn region iText start='<i>' end='</i>' cchar=* |
]])
end)
end) -- a region of text (implicit concealing)
end) -- match and conceal
- describe("let the conceal level be", function()
+ describe("let the conceal level be", function()
before_each(function()
- insert("// No Conceal\n")
- insert('"Conceal without a cchar"\n')
- insert("+ With cchar\n\n")
+ insert("// No Conceal\n")
+ insert('"Conceal without a cchar"\n')
+ insert("+ With cchar\n\n")
execute("syn match noConceal '^//.*$'")
execute("syn match concealNoCchar '\".\\{-}\"$' conceal")
execute("syn match concealWCchar '^+.\\{-}$' conceal cchar=C")
end)
-
- it("0. No concealing.", function()
+
+ it("0. No concealing.", function()
execute("let &conceallevel=0")
screen:expect([[
// No Conceal |
@@ -271,14 +275,14 @@ describe('Screen', function()
+ With cchar |
|
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:let &conceallevel=0 |
]])
end)
-
+
it("1. Conceal using cchar or reference listchars.", function()
execute("let &conceallevel=1")
screen:expect([[
@@ -287,14 +291,14 @@ describe('Screen', function()
{1:C} |
|
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:let &conceallevel=1 |
]])
end)
-
+
it("2. Hidden unless cchar is set.", function()
execute("let &conceallevel=2")
screen:expect([[
@@ -303,15 +307,15 @@ describe('Screen', function()
{1:C} |
|
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:let &conceallevel=2 |
]])
end)
-
- it("3. Hide all concealed text.", function()
+
+ it("3. Hide all concealed text.", function()
execute("let &conceallevel=3")
screen:expect([[
// No Conceal |
@@ -319,10 +323,10 @@ describe('Screen', function()
|
|
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
:let &conceallevel=3 |
]])
end)
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index c57d4abcbf..6a6dc99c3d 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -1,8 +1,10 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
local funcs = helpers.funcs
+if helpers.pending_win32(pending) then return end
+
describe("'wildmode'", function()
local screen
@@ -39,7 +41,7 @@ describe('command line completion', function()
clear()
screen = Screen.new(40, 5)
screen:attach()
- screen:set_default_attr_ignore({{bold=true, foreground=Screen.colors.Blue}})
+ screen:set_default_attr_ids({[1]={bold=true, foreground=Screen.colors.Blue}})
end)
after_each(function()
@@ -55,9 +57,9 @@ describe('command line completion', function()
feed(':!<tab><bs>')
screen:expect([[
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
:!Xtest-functional-viml-compl-dir^ |
]])
end)