local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear = helpers.clear local command = helpers.command local eq = helpers.eq local eval = helpers.eval local feed = helpers.feed local funcs = helpers.funcs local wait = helpers.wait describe('search cmdline', function() local screen before_each(function() clear() command('set nohlsearch') screen = Screen.new(20, 3) screen:attach() screen:set_default_attr_ids({ inc = {reverse = true}, err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, more = { bold = true, foreground = Screen.colors.SeaGreen4 }, tilde = { bold = true, foreground = Screen.colors.Blue1 }, hl = { background = Screen.colors.Yellow }, }) end) local function tenlines() funcs.setline(1, { ' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there', ' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar' }) command('1') end it('history can be navigated with /', function() tenlines() command('set noincsearch') feed('/foobar') feed('/the') eq('the', eval('@/')) feed('/thes') eq('foobar', eval('@/')) end) describe('can traverse matches', function() before_each(tenlines) local function forwarditer(wrapscan) command('set incsearch '..wrapscan) feed('/the') screen:expect([[ 1 | 2 {inc:the}se | /the^ | ]]) feed('') screen:expect([[ 2 these | 3 {inc:the} | /the^ | ]]) eq({0, 0, 0, 0}, funcs.getpos('"')) feed('') screen:expect([[ 3 the | 4 {inc:the}ir | /the^ | ]]) feed('') screen:expect([[ 4 their | 5 {inc:the}re | /the^ | ]]) feed('') screen:expect([[ 5 there | 6 {inc:the}ir | /the^ | ]]) feed('') screen:expect([[ 6 their | 7 {inc:the} | /the^ | ]]) feed('') screen:expect([[ 7 the | 8 {inc:the}m | /the^ | ]]) feed('') screen:expect([[ 8 them | 9 {inc:the}se | /the^ | ]]) screen.bell = false feed('') if wrapscan == 'wrapscan' then screen:expect([[ 2 {inc:the}se | 3 the | /the^ | ]]) else screen:expect{grid=[[ 8 them | 9 {inc:the}se | /the^ | ]], condition=function() eq(true, screen.bell) end} feed('') eq({0, 0, 0, 0}, funcs.getpos('"')) end end local function backiter(wrapscan) command('set incsearch '..wrapscan) command('$') feed('?the') screen:expect([[ 9 {inc:the}se | 10 foobar | ?the^ | ]]) screen.bell = false if wrapscan == 'wrapscan' then feed('') screen:expect([[ 2 {inc:the}se | 3 the | ?the^ | ]]) feed('') screen:expect([[ 2 ^these | 3 the | ?the | ]]) else feed('') screen:expect{grid=[[ 9 {inc:the}se | 10 foobar | ?the^ | ]], condition=function() eq(true, screen.bell) end} feed('') screen:expect([[ 9 ^these | 10 foobar | ?the | ]]) end command('$') feed('?the') screen:expect([[ 9 {inc:the}se | 10 foobar | ?the^ | ]]) feed('') screen:expect([[ 8 {inc:the}m | 9 these | ?the^ | ]]) for i = 1, 6 do feed('') -- Avoid sleep just before expect, otherwise expect will take the full -- timeout if i ~= 6 then screen:sleep(1) end end screen:expect([[ 2 {inc:the}se | 3 the | ?the^ | ]]) screen.bell = false feed('') if wrapscan == 'wrapscan' then screen:expect([[ 9 {inc:the}se | 10 foobar | ?the^ | ]]) else screen:expect{grid=[[ 2 {inc:the}se | 3 the | ?the^ | ]], condition=function() eq(true, screen.bell) end} end end it("using and 'nowrapscan'", function() forwarditer('nowrapscan') end) it("using and 'wrapscan'", function() forwarditer('wrapscan') end) it("using and 'nowrapscan'", function() backiter('nowrapscan') end) it("using and 'wrapscan'", function() backiter('wrapscan') end) end) it('expands pattern with ', function() tenlines() command('set incsearch wrapscan') feed('/the') screen:expect([[ 1 | 2 {inc:the}se | /the^ | ]]) feed('') screen:expect([[ 1 | 2 {inc:thes}e | /thes^ | ]]) feed('') screen:expect([[ 9 {inc:thes}e | 10 foobar | /thes^ | ]]) feed('') screen:expect([[ 2 {inc:thes}e | 3 the | /thes^ | ]]) feed('') screen:expect([[ 2 ^these | 3 the | /thes | ]]) command('1') command('set nowrapscan') feed('/the') screen:expect([[ 1 | 2 {inc:the}se | /the^ | ]]) feed('') screen:expect([[ 1 | 2 {inc:thes}e | /thes^ | ]]) feed('') screen:expect([[ 9 {inc:thes}e | 10 foobar | /thes^ | ]]) feed('') screen:expect([[ 9 ^these | 10 foobar | /thes | ]]) end) it('reduces pattern with and keeps cursor position', function() tenlines() command('set incsearch wrapscan') -- First match feed('/thei') screen:expect([[ 4 {inc:thei}r | 5 there | /thei^ | ]]) -- Match from initial cursor position when modifying search feed('') screen:expect([[ 1 | 2 {inc:the}se | /the^ | ]]) -- New text advances to next match feed('s') screen:expect([[ 1 | 2 {inc:thes}e | /thes^ | ]]) -- Stay on this match when deleting a character feed('') screen:expect([[ 1 | 2 {inc:the}se | /the^ | ]]) -- Advance to previous match feed('') screen:expect([[ 9 {inc:the}se | 10 foobar | /the^ | ]]) -- Extend search to include next character feed('') screen:expect([[ 9 {inc:thes}e | 10 foobar | /thes^ | ]]) -- Deleting all characters resets the cursor position feed('') screen:expect([[ 1 | 2 these | /^ | ]]) feed('the') screen:expect([[ 1 | 2 {inc:the}se | /the^ | ]]) feed('\\>') screen:expect([[ 2 these | 3 {inc:the} | /the\>^ | ]]) end) it('can traverse matches in the same line with /', function() funcs.setline(1, { ' 1', ' 2 these', ' 3 the theother' }) command('1') command('set incsearch') -- First match feed('/the') screen:expect([[ 1 | 2 {inc:the}se | /the^ | ]]) -- Next match, different line feed('') screen:expect([[ 2 these | 3 {inc:the} theother | /the^ | ]]) -- Next match, same line feed('') screen:expect([[ 2 these | 3 the {inc:the}other | /the^ | ]]) feed('') screen:expect([[ 2 these | 3 the theo{inc:the}r | /the^ | ]]) -- Previous match, same line feed('') screen:expect([[ 2 these | 3 the {inc:the}other | /the^ | ]]) feed('') screen:expect([[ 2 these | 3 {inc:the} theother | /the^ | ]]) -- Previous match, different line feed('') screen:expect([[ 2 {inc:the}se | 3 the theother | /the^ | ]]) end) it('keeps the view after deleting a char from the search', function() screen:try_resize(20, 6) tenlines() feed('/foo') screen:expect([[ 6 their | 7 the | 8 them | 9 these | 10 {inc:foo}bar | /foo^ | ]]) feed('') screen:expect([[ 6 their | 7 the | 8 them | 9 these | 10 {inc:fo}obar | /fo^ | ]]) feed('') screen:expect([[ 6 their | 7 the | 8 them | 9 these | 10 ^foobar | /fo | ]]) eq({lnum = 10, leftcol = 0, col = 4, topfill = 0, topline = 6, coladd = 0, skipcol = 0, curswant = 4}, funcs.winsaveview()) end) it('restores original view after failed search', function() screen:try_resize(40, 3) tenlines() feed('0') feed('/foo') screen:expect([[ 9 these | 10 {inc:foo}bar | /foo^ | ]]) feed('') screen:expect([[ 1 | 2 these | /^ | ]]) feed('') screen:expect([[ / | {err:E35: No previous regular expression} | {more:Press ENTER or type command to continue}^ | ]]) feed('') eq({lnum = 1, leftcol = 0, col = 0, topfill = 0, topline = 1, coladd = 0, skipcol = 0, curswant = 0}, funcs.winsaveview()) end) it("CTRL-G with 'incsearch' and ? goes in the right direction", function() -- oldtest: Test_search_cmdline4(). screen:try_resize(40, 4) command('enew!') funcs.setline(1, {' 1 the first', ' 2 the second', ' 3 the third'}) command('set laststatus=0 shortmess+=s') command('set incsearch') command('$') -- Send the input in chunks, so the cmdline logic regards it as -- "interactive". This mimics Vim's test_override("char_avail"). -- (See legacy test: test_search.vim) feed('?the') wait() feed('') wait() feed('') screen:expect([[ 1 the first | 2 the second | 3 ^the third | ?the | ]]) command('$') feed('?the') wait() feed('') wait() feed('') wait() feed('') screen:expect([[ 1 ^the first | 2 the second | 3 the third | ?the | ]]) command('$') feed('?the') wait() feed('') wait() feed('') wait() feed('') wait() feed('') screen:expect([[ 1 the first | 2 ^the second | 3 the third | ?the | ]]) command('$') feed('?the') wait() feed('') wait() feed('') screen:expect([[ 1 ^the first | 2 the second | 3 the third | ?the | ]]) command('$') feed('?the') wait() feed('') wait() feed('') wait() feed('') screen:expect([[ 1 the first | 2 the second | 3 ^the third | ?the | ]]) command('$') feed('?the') wait() feed('') wait() feed('') wait() feed('') wait() feed('') screen:expect([[ 1 the first | 2 ^the second | 3 the third | ?the | ]]) end) it('incsearch works with :sort', function() -- oldtest: Test_incsearch_sort_dump(). screen:try_resize(20, 4) command('set incsearch hlsearch scrolloff=0') funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'}) feed(':sort ni u /on') screen:expect([[ another {inc:on}e 2 | that {hl:on}e 3 | the {hl:on}e 1 | :sort ni u /on^ | ]]) feed('') end) end)