mirror of
https://github.com/neovim/neovim.git
synced 2024-12-28 14:31:13 -07:00
54d5e90a2b
Problem: Redraw problem when using 'incsearch'.
Solution: Save the current view when deleting characters. (Christian
Brabandt) Fix that the '" mark is set in the wrong position. Don't
change the search start when using BS.
dda933d06c
475 lines
12 KiB
Lua
475 lines
12 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
|
|
|
|
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}
|
|
})
|
|
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^ |
|
|
]])
|
|
feed('<C-G>')
|
|
if wrapscan == 'wrapscan' then
|
|
screen:expect([[
|
|
2 {inc:the}se |
|
|
3 the |
|
|
/the^ |
|
|
]])
|
|
else
|
|
screen:expect([[
|
|
8 them |
|
|
9 {inc:the}se |
|
|
/the^ |
|
|
]])
|
|
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^ |
|
|
]])
|
|
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([[
|
|
9 {inc:the}se |
|
|
10 foobar |
|
|
?the^ |
|
|
]])
|
|
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^ |
|
|
]])
|
|
feed('<C-T>')
|
|
if wrapscan == 'wrapscan' then
|
|
screen:expect([[
|
|
9 {inc:the}se |
|
|
10 foobar |
|
|
?the^ |
|
|
]])
|
|
else
|
|
screen:expect([[
|
|
2 {inc:the}se |
|
|
3 the |
|
|
?the^ |
|
|
]])
|
|
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:detach()
|
|
screen = Screen.new(20, 6)
|
|
screen:attach()
|
|
screen:set_default_attr_ids({
|
|
inc = {reverse = true}
|
|
})
|
|
screen:set_default_attr_ignore({
|
|
{bold=true, reverse=true}, {bold=true, foreground=Screen.colors.Blue1}
|
|
})
|
|
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:detach()
|
|
screen = Screen.new(40, 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 },
|
|
})
|
|
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)
|
|
end)
|