local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, command = helpers.clear, helpers.feed, helpers.command local eq = helpers.eq local insert = helpers.insert local poke_eventloop = helpers.poke_eventloop describe('Screen', function() local screen before_each(function() clear() screen = Screen.new(nil,10) screen:attach() screen:set_default_attr_ids( { [0] = {bold=true, foreground=Screen.colors.Blue}, [1] = {foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray}, [2] = {bold = true, reverse = true}, [3] = {reverse = true}, [4] = {bold = true}, [5] = {background = Screen.colors.Yellow}, [6] = {background = Screen.colors.LightGrey}, } ) end) describe("match and conceal", function() before_each(function() command("let &conceallevel=1") end) describe("multiple", function() before_each(function() insert([[ && && && && && && ]]) command("syn match dAmpersand '[&][&]' conceal cchar=∧") end) it("double characters.", function() screen:expect([[ {1:∧} | {1:∧} | {1:∧} | {1:∧} | {1:∧} | {1:∧} | ^ | {0:~ }| {0:~ }| | ]]) end) it('double characters and move the cursor one line up.', function() feed("k") screen:expect([[ {1:∧} | {1:∧} | {1:∧} | {1:∧} | {1:∧} | ^&& | | {0:~ }| {0:~ }| | ]]) end) it('double characters and move the cursor to the beginning of the file.', function() feed("gg") screen:expect([[ ^&& | {1:∧} | {1:∧} | {1:∧} | {1:∧} | {1:∧} | | {0:~ }| {0:~ }| | ]]) end) it('double characters and move the cursor to the second line in the file.', function() feed("ggj") screen:expect([[ {1:∧} | ^&& | {1:∧} | {1:∧} | {1:∧} | {1:∧} | | {0:~ }| {0:~ }| | ]]) end) 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:∧} | {1:∧} | {1:∧} | {1:∧} | {1:∧} | {1:∧} | ^ | {0:~ }| {0:~ }| | ]]) end) end) -- multiple it("keyword instances in initially in the document.", function() feed("2ilambda") command("let &conceallevel=1") command("syn keyword kLambda lambda conceal cchar=λ") screen:expect([[ {1:λ} | {1:λ} | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) end) -- Keyword describe("regions in the document", function() before_each(function() feed("2") insert(" a region of text \n") command("let &conceallevel=1") end) it('initially and conceal it.', function() command("syn region rText start='' end='' conceal cchar=R") screen:expect([[ {1:R} | {1:R} | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) end) it('initially and conceal its start tag and end tag.', function() -- concealends has a known bug (todo.txt) where the first match won't -- be replaced with cchar. command("syn region rText matchgroup=rMatch start='' end='' concealends cchar=-") screen:expect([[ {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() command("syn region rText contains=rText matchgroup=rMatch start='' end='' concealends cchar=-") insert(" A region with a nested nested region. \n") screen:expect([[ {1: } a region of text {1:-} | {1: } a region of text {1:-} | {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() command("syntax conceal on") feed("2") insert(" a region of text \n") command("syn region rText start='' end='' cchar=-") end) it("and turn on implicit concealing", function() screen:expect([[ {1:-} | {1:-} | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) end) it("and then turn on, then off, and then back on implicit concealing.", function() command("syntax conceal off") feed("2") insert(" italian text \n") command("syn region iText start='' end='' cchar=*") screen:expect([[ {1:-} | {1:-} | italian text | italian text | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) command("syntax conceal on") command("syn region iText start='' end='' cchar=*") screen:expect([[ {1:-} | {1:-} | {1:*} | {1:*} | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) end) end) -- a region of text (implicit concealing) it("cursor position is correct when entering Insert mode with cocu=ni #13916", function() insert([[foobarfoobarfoobar]]) -- move to end of line feed("$") command("set concealcursor=ni") command("syn match Foo /foobar/ conceal cchar=&") screen:expect([[ {1:&&&}^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) feed("i") -- cursor should stay in place, not jump to column 16 screen:expect([[ {1:&&&}^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| {4:-- INSERT --} | ]]) end) end) -- match and conceal 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") command("syn match noConceal '^//.*$'") command("syn match concealNoCchar '\".\\{-}\"$' conceal") command("syn match concealWCchar '^+.\\{-}$' conceal cchar=C") end) it("0. No concealing.", function() command("let &conceallevel=0") screen:expect([[ // No Conceal | "Conceal without a cchar" | + With cchar | | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) end) it("1. Conceal using cchar or reference listchars.", function() command("let &conceallevel=1") screen:expect([[ // No Conceal | {1: } | {1:C} | | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) end) it("2. Hidden unless cchar is set.", function() command("let &conceallevel=2") screen:expect([[ // No Conceal | | {1:C} | | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) end) it("3. Hide all concealed text.", function() command("let &conceallevel=3") screen:expect([[ // No Conceal | | | | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]) end) end) -- conceallevel describe("cursor movement", function() before_each(function() command("syn keyword concealy barf conceal cchar=b") command("set cole=2") feed('5Ofoo barf bar barf eggs') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo barf bar barf egg^s | | {0:~ }| {0:~ }| {0:~ }| | ]]) end) it('between windows', function() feed('k') command("split") screen:expect([[ foo {1:b} bar {1:b} eggs | foo barf bar barf egg^s | foo {1:b} bar {1:b} eggs | | {2:[No Name] [+] }| foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | {3:[No Name] [+] }| | ]]) feed('w') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {3:[No Name] [+] }| foo {1:b} bar {1:b} eggs | foo barf bar barf egg^s | foo {1:b} bar {1:b} eggs | {2:[No Name] [+] }| | ]]) end) it('in insert mode', function() feed('i') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo barf bar barf egg^s | | {0:~ }| {0:~ }| {0:~ }| {4:-- INSERT --} | ]]) feed('') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo barf bar barf egg^s | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| {4:-- INSERT --} | ]]) end) it('between modes cocu=iv', function() command('set cocu=iv') feed('gg') screen:expect([[ ^foo barf bar barf eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) feed('i') screen:expect([[ ^foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| {4:-- INSERT --} | ]]) feed('') screen:expect([[ ^foo barf bar barf eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) feed('v') screen:expect([[ ^foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| {4:-- VISUAL --} | ]]) feed('') screen:expect([[ ^foo barf bar barf eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) end) it('between modes cocu=n', function() command('set cocu=n') feed('gg') screen:expect([[ ^foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) feed('i') screen:expect([[ ^foo barf bar barf eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| {4:-- INSERT --} | ]]) feed('') screen:expect([[ ^foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) feed('v') screen:expect([[ ^foo barf bar barf eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| {4:-- VISUAL --} | ]]) feed('') screen:expect([[ ^foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) end) it('and open line', function() feed('o') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | ^ | | {0:~ }| {0:~ }| {4:-- INSERT --} | ]]) end) it('and open line cocu=i', function() command('set cocu=i') feed('o') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | ^ | | {0:~ }| {0:~ }| {4:-- INSERT --} | ]]) end) describe('with incsearch', function() before_each(function() command('set incsearch hlsearch') feed('2GA x3GA xygg') screen:expect([[ ^foo barf bar barf eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) end) it('cocu=', function() feed('/') screen:expect([[ foo barf bar barf eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /^ | ]]) feed('x') screen:expect([[ foo {1:b} bar {1:b} eggs | foo barf bar barf eggs {3:x} | foo {1:b} bar {1:b} eggs {5:x}y | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /x^ | ]]) feed('y') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs x | foo barf bar barf eggs {3:xy} | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /xy^ | ]]) feed('') screen:expect([[ foo barf bar barf eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /^ | ]]) end) it('cocu=c', function() command('set cocu=c') feed('/') -- NB: we don't do this redraw. Probably best to still skip it, -- to avoid annoying distraction from the cmdline screen:expect([[ foo barf bar barf eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /^ | ]]) feed('x') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs {3:x} | foo {1:b} bar {1:b} eggs {5:x}y | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /x^ | ]]) feed('y') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs {3:xy} | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /xy^ | ]]) feed('') screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /^ | ]]) feed('') screen:expect([[ ^foo barf bar barf eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) end) it('cocu=n', function() command('set cocu=n') screen:expect([[ ^foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) feed('/') -- NB: we don't do this redraw. Probably best to still skip it, -- to avoid annoying distraction from the cmdline screen:expect([[ foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /^ | ]]) feed('x') screen:expect([[ foo {1:b} bar {1:b} eggs | foo barf bar barf eggs {3:x} | foo {1:b} bar {1:b} eggs {5:x}y | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /x^ | ]]) feed('') screen:expect([[ foo barf bar barf eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| /^ | ]]) feed('') screen:expect([[ ^foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs x | foo {1:b} bar {1:b} eggs xy | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | | {0:~ }| {0:~ }| {0:~ }| | ]]) end) end) it('redraws properly with concealcursor in visual mode', function() command('set concealcursor=v conceallevel=2') feed('10Ofoo barf bar barf eggs') feed(':3o aggV') screen:expect{grid=[[ ^f{6:oo }{1:b}{6: bar }{1:b}{6: eggs} | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | a | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | {4:-- VISUAL LINE --} | ]]} feed(string.rep('j', 15)) screen:expect{grid=[[ {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | ^f{6:oo }{1:b}{6: bar }{1:b}{6: eggs} | {4:-- VISUAL LINE --} | ]]} feed(string.rep('k', 15)) screen:expect{grid=[[ ^f{6:oo }{1:b}{6: bar }{1:b}{6: eggs} | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | a | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | foo {1:b} bar {1:b} eggs | {4:-- VISUAL LINE --} | ]]} end) end) it('redraws not too much with conceallevel=1', function() command('set conceallevel=1') command('set redrawdebug+=nodelta') insert([[ aaa bbb ccc ]]) screen:expect{grid=[[ aaa | bbb | ccc | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]} -- XXX: hack to get notifications, and check only a single line is -- updated. Could use next_msg() also. local orig_handle_grid_line = screen._handle_grid_line local grid_lines = {} function screen._handle_grid_line(self, grid, row, col, items) table.insert(grid_lines, {row, col, items}) orig_handle_grid_line(self, grid, row, col, items) end feed('k') screen:expect{grid=[[ aaa | bbb | ^ccc | | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]} eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) end) it('K_EVENT should not cause extra redraws with concealcursor #13196', function() command('set conceallevel=1') command('set concealcursor=nv') command('set redrawdebug+=nodelta') insert([[ aaa bbb ccc ]]) screen:expect{grid=[[ aaa | bbb | ccc | ^ | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]} -- XXX: hack to get notifications, and check only a single line is -- updated. Could use next_msg() also. local orig_handle_grid_line = screen._handle_grid_line local grid_lines = {} function screen._handle_grid_line(self, grid, row, col, items) table.insert(grid_lines, {row, col, items}) orig_handle_grid_line(self, grid, row, col, items) end feed('k') screen:expect{grid=[[ aaa | bbb | ^ccc | | {0:~ }| {0:~ }| {0:~ }| {0:~ }| {0:~ }| | ]]} eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) poke_eventloop() -- causes K_EVENT key screen:expect_unchanged() eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) end) -- Copy of Test_cursor_column_in_concealed_line_after_window_scroll in -- test/functional/ui/syntax_conceal_spec.lua. describe('concealed line after window scroll', function() after_each(function() command(':qall!') os.remove('Xcolesearch') end) it('has the correct cursor column', function() insert([[ 3split let m = matchadd('Conceal', '=') setl conceallevel=2 concealcursor=nc normal gg "==expr== ]]) command('write Xcolesearch') feed(":so %") -- Jump to something that is beyond the bottom of the window, -- so there's a scroll down. feed("/expr") -- Are the concealed parts of the current line really hidden? -- Is the window's cursor column properly updated for hidden -- parts of the current line? screen:expect{grid=[[ setl conceallevel2 concealcursornc | normal gg | "{5:^expr} | {2:Xcolesearch }| normal gg | "=={5:expr}== | | {0:~ }| {3:Xcolesearch }| /expr | ]]} end) end) end)