mirror of
https://github.com/neovim/neovim.git
synced 2025-01-02 17:33:28 -07:00
4987311fb5
It is perfectly fine and expected to detach from the screen just by the UI disconnecting from nvim or exiting nvim. Just keep detach() in screen_basic_spec, to get some coverage of the detach method itself. This avoids hang on failure in many situations (though one could argue that detach() should be "fast", or at least "as fast as resize", which works in press-return already). Never use detach() just to change the size of the screen, try_resize() method exists for that specifically.
574 lines
14 KiB
Lua
574 lines
14 KiB
Lua
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 },
|
|
})
|
|
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')
|
|
wait()
|
|
feed('<c-g>')
|
|
wait()
|
|
feed('<cr>')
|
|
screen:expect([[
|
|
1 the first |
|
|
2 the second |
|
|
3 ^the third |
|
|
?the |
|
|
]])
|
|
|
|
command('$')
|
|
feed('?the')
|
|
wait()
|
|
feed('<c-g>')
|
|
wait()
|
|
feed('<c-g>')
|
|
wait()
|
|
feed('<cr>')
|
|
screen:expect([[
|
|
1 ^the first |
|
|
2 the second |
|
|
3 the third |
|
|
?the |
|
|
]])
|
|
|
|
command('$')
|
|
feed('?the')
|
|
wait()
|
|
feed('<c-g>')
|
|
wait()
|
|
feed('<c-g>')
|
|
wait()
|
|
feed('<c-g>')
|
|
wait()
|
|
feed('<cr>')
|
|
screen:expect([[
|
|
1 the first |
|
|
2 ^the second |
|
|
3 the third |
|
|
?the |
|
|
]])
|
|
|
|
command('$')
|
|
feed('?the')
|
|
wait()
|
|
feed('<c-t>')
|
|
wait()
|
|
feed('<cr>')
|
|
screen:expect([[
|
|
1 ^the first |
|
|
2 the second |
|
|
3 the third |
|
|
?the |
|
|
]])
|
|
|
|
command('$')
|
|
feed('?the')
|
|
wait()
|
|
feed('<c-t>')
|
|
wait()
|
|
feed('<c-t>')
|
|
wait()
|
|
feed('<cr>')
|
|
screen:expect([[
|
|
1 the first |
|
|
2 the second |
|
|
3 ^the third |
|
|
?the |
|
|
]])
|
|
|
|
command('$')
|
|
feed('?the')
|
|
wait()
|
|
feed('<c-t>')
|
|
wait()
|
|
feed('<c-t>')
|
|
wait()
|
|
feed('<c-t>')
|
|
wait()
|
|
feed('<cr>')
|
|
screen:expect([[
|
|
1 the first |
|
|
2 ^the second |
|
|
3 the third |
|
|
?the |
|
|
]])
|
|
end)
|
|
end)
|