123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643 |
- 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 poke_eventloop = helpers.poke_eventloop
- 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 <C-N>/<C-P>', function()
- tenlines()
- command('set noincsearch')
- feed('/foobar<CR>')
- feed('/the<CR>')
- eq('the', eval('@/'))
- feed('/thes<C-P><C-P><CR>')
- 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('<C-G>')
- screen:expect([[
- 2 these |
- 3 {inc:the} |
- /the^ |
- ]])
- eq({0, 0, 0, 0}, funcs.getpos('"'))
- feed('<C-G>')
- screen:expect([[
- 3 the |
- 4 {inc:the}ir |
- /the^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 4 their |
- 5 {inc:the}re |
- /the^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 5 there |
- 6 {inc:the}ir |
- /the^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 6 their |
- 7 {inc:the} |
- /the^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 7 the |
- 8 {inc:the}m |
- /the^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 8 them |
- 9 {inc:the}se |
- /the^ |
- ]])
- screen.bell = false
- feed('<C-G>')
- 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('<CR>')
- 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('<C-G>')
- screen:expect([[
- 2 {inc:the}se |
- 3 the |
- ?the^ |
- ]])
- feed('<CR>')
- screen:expect([[
- 2 ^these |
- 3 the |
- ?the |
- ]])
- else
- feed('<C-G>')
- screen:expect{grid=[[
- 9 {inc:the}se |
- 10 foobar |
- ?the^ |
- ]], condition=function()
- eq(true, screen.bell)
- end}
- feed('<CR>')
- screen:expect([[
- 9 ^these |
- 10 foobar |
- ?the |
- ]])
- end
- command('$')
- feed('?the')
- screen:expect([[
- 9 {inc:the}se |
- 10 foobar |
- ?the^ |
- ]])
- feed('<C-T>')
- screen:expect([[
- 8 {inc:the}m |
- 9 these |
- ?the^ |
- ]])
- for i = 1, 6 do
- feed('<C-T>')
- -- 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('<C-T>')
- 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 <C-G> and 'nowrapscan'", function()
- forwarditer('nowrapscan')
- end)
- it("using <C-G> and 'wrapscan'", function()
- forwarditer('wrapscan')
- end)
- it("using <C-T> and 'nowrapscan'", function()
- backiter('nowrapscan')
- end)
- it("using <C-T> and 'wrapscan'", function()
- backiter('wrapscan')
- end)
- end)
- it('expands pattern with <C-L>', function()
- tenlines()
- command('set incsearch wrapscan')
- feed('/the')
- screen:expect([[
- 1 |
- 2 {inc:the}se |
- /the^ |
- ]])
- feed('<C-L>')
- screen:expect([[
- 1 |
- 2 {inc:thes}e |
- /thes^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 9 {inc:thes}e |
- 10 foobar |
- /thes^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 2 {inc:thes}e |
- 3 the |
- /thes^ |
- ]])
- feed('<CR>')
- screen:expect([[
- 2 ^these |
- 3 the |
- /thes |
- ]])
- command('1')
- command('set nowrapscan')
- feed('/the')
- screen:expect([[
- 1 |
- 2 {inc:the}se |
- /the^ |
- ]])
- feed('<C-L>')
- screen:expect([[
- 1 |
- 2 {inc:thes}e |
- /thes^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 9 {inc:thes}e |
- 10 foobar |
- /thes^ |
- ]])
- feed('<C-G><CR>')
- screen:expect([[
- 9 ^these |
- 10 foobar |
- /thes |
- ]])
- end)
- it('reduces pattern with <BS> 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('<BS>')
- 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('<BS>')
- screen:expect([[
- 1 |
- 2 {inc:the}se |
- /the^ |
- ]])
- -- Advance to previous match
- feed('<C-T>')
- screen:expect([[
- 9 {inc:the}se |
- 10 foobar |
- /the^ |
- ]])
- -- Extend search to include next character
- feed('<C-L>')
- screen:expect([[
- 9 {inc:thes}e |
- 10 foobar |
- /thes^ |
- ]])
- -- Deleting all characters resets the cursor position
- feed('<BS><BS><BS><BS>')
- 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 <C-G>/<C-T>', 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('<C-G>')
- screen:expect([[
- 2 these |
- 3 {inc:the} theother |
- /the^ |
- ]])
- -- Next match, same line
- feed('<C-G>')
- screen:expect([[
- 2 these |
- 3 the {inc:the}other |
- /the^ |
- ]])
- feed('<C-G>')
- screen:expect([[
- 2 these |
- 3 the theo{inc:the}r |
- /the^ |
- ]])
- -- Previous match, same line
- feed('<C-T>')
- screen:expect([[
- 2 these |
- 3 the {inc:the}other |
- /the^ |
- ]])
- feed('<C-T>')
- screen:expect([[
- 2 these |
- 3 {inc:the} theother |
- /the^ |
- ]])
- -- Previous match, different line
- feed('<C-T>')
- 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('<BS>')
- screen:expect([[
- 6 their |
- 7 the |
- 8 them |
- 9 these |
- 10 {inc:fo}obar |
- /fo^ |
- ]])
- feed('<CR>')
- 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('<C-W>')
- screen:expect([[
- 1 |
- 2 these |
- /^ |
- ]])
- feed('<CR>')
- screen:expect([[
- / |
- {err:E35: No previous regular expression} |
- {more:Press ENTER or type command to continue}^ |
- ]])
- feed('<CR>')
- 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')
- poke_eventloop()
- feed('<c-g>')
- poke_eventloop()
- feed('<cr>')
- screen:expect([[
- 1 the first |
- 2 the second |
- 3 ^the third |
- ?the |
- ]])
- command('$')
- feed('?the')
- poke_eventloop()
- feed('<c-g>')
- poke_eventloop()
- feed('<c-g>')
- poke_eventloop()
- feed('<cr>')
- screen:expect([[
- 1 ^the first |
- 2 the second |
- 3 the third |
- ?the |
- ]])
- command('$')
- feed('?the')
- poke_eventloop()
- feed('<c-g>')
- poke_eventloop()
- feed('<c-g>')
- poke_eventloop()
- feed('<c-g>')
- poke_eventloop()
- feed('<cr>')
- screen:expect([[
- 1 the first |
- 2 ^the second |
- 3 the third |
- ?the |
- ]])
- command('$')
- feed('?the')
- poke_eventloop()
- feed('<c-t>')
- poke_eventloop()
- feed('<cr>')
- screen:expect([[
- 1 ^the first |
- 2 the second |
- 3 the third |
- ?the |
- ]])
- command('$')
- feed('?the')
- poke_eventloop()
- feed('<c-t>')
- poke_eventloop()
- feed('<c-t>')
- poke_eventloop()
- feed('<cr>')
- screen:expect([[
- 1 the first |
- 2 the second |
- 3 ^the third |
- ?the |
- ]])
- command('$')
- feed('?the')
- poke_eventloop()
- feed('<c-t>')
- poke_eventloop()
- feed('<c-t>')
- poke_eventloop()
- feed('<c-t>')
- poke_eventloop()
- feed('<cr>')
- 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('<esc>')
- end)
- it('incsearch works with :vimgrep family', function()
- -- oldtest: Test_incsearch_vimgrep_dump().
- screen:try_resize(30, 4)
- command('set incsearch hlsearch scrolloff=0')
- funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
- feed(':vimgrep on')
- screen:expect([[
- another {inc:on}e 2 |
- that {hl:on}e 3 |
- the {hl:on}e 1 |
- :vimgrep on^ |
- ]])
- feed('<esc>')
- feed(':vimg /on/ *.txt')
- screen:expect([[
- another {inc:on}e 2 |
- that {hl:on}e 3 |
- the {hl:on}e 1 |
- :vimg /on/ *.txt^ |
- ]])
- feed('<esc>')
- feed(':vimgrepadd "\\<LT>on')
- screen:expect([[
- another {inc:on}e 2 |
- that {hl:on}e 3 |
- the {hl:on}e 1 |
- :vimgrepadd "\<on^ |
- ]])
- feed('<esc>')
- feed(':lv "tha')
- screen:expect([[
- another one 2 |
- {inc:tha}t one 3 |
- the one 1 |
- :lv "tha^ |
- ]])
- feed('<esc>')
- feed(':lvimgrepa "the" **/*.txt')
- screen:expect([[
- ano{inc:the}r one 2 |
- that one 3 |
- {hl:the} one 1 |
- :lvimgrepa "the" **/*.txt^ |
- ]])
- feed('<esc>')
- end)
- end)
|