diff options
Diffstat (limited to 'test/functional/ui')
-rw-r--r-- | test/functional/ui/bufhl_spec.lua | 208 | ||||
-rw-r--r-- | test/functional/ui/highlight_spec.lua | 365 | ||||
-rw-r--r-- | test/functional/ui/inccommand_spec.lua | 1623 | ||||
-rw-r--r-- | test/functional/ui/input_spec.lua | 4 | ||||
-rw-r--r-- | test/functional/ui/mouse_spec.lua | 799 | ||||
-rw-r--r-- | test/functional/ui/output_spec.lua | 68 | ||||
-rw-r--r-- | test/functional/ui/quickfix_spec.lua | 196 | ||||
-rw-r--r-- | test/functional/ui/screen.lua | 206 | ||||
-rw-r--r-- | test/functional/ui/screen_basic_spec.lua | 562 | ||||
-rw-r--r-- | test/functional/ui/searchhl_spec.lua | 201 | ||||
-rw-r--r-- | test/functional/ui/sign_spec.lua | 36 | ||||
-rw-r--r-- | test/functional/ui/syntax_conceal_spec.lua | 186 | ||||
-rw-r--r-- | test/functional/ui/wildmode_spec.lua | 12 |
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) |