mirror of
https://github.com/neovim/neovim.git
synced 2026-09-03 21:00:34 +00:00
Problem: With 'wildmode' set to list:full the matches are listed but the
wildmenu is not shown, although it is "full" that starts
wildmenu mode (zeertzjq).
Solution: List the matches and show the menu, as the two behaviors in
the same phase ask for. The menu is left to the phases that
ask for it, so that "list" on its own still only lists
(Hirohito Higashi).
fixes: vim/vim#21196
closes: vim/vim#21205
fa1ddffcce
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
379 lines
15 KiB
Lua
379 lines
15 KiB
Lua
-- Tests for (protocol-driven) ui2, intended to replace the legacy message grid UI.
|
|
|
|
local t = require('test.testutil')
|
|
local n = require('test.functional.testnvim')()
|
|
local Screen = require('test.functional.ui.screen')
|
|
|
|
local describe, it, before_each = t.describe, t.it, t.before_each
|
|
local clear, exec, exec_lua, feed = n.clear, n.exec, n.exec_lua, n.feed
|
|
|
|
describe('cmdline2', function()
|
|
local screen
|
|
before_each(function()
|
|
clear()
|
|
screen = Screen.new()
|
|
screen:add_extra_attr_ids({
|
|
[100] = { foreground = Screen.colors.Magenta1, bold = true },
|
|
[101] = { background = Screen.colors.Yellow, foreground = Screen.colors.Grey0 },
|
|
[102] = { background = Screen.colors.Cyan1, foreground = Screen.colors.SlateBlue },
|
|
})
|
|
exec_lua(function()
|
|
require('vim._core.ui2').enable({})
|
|
end)
|
|
end)
|
|
|
|
it("no crash for invalid grid after 'cmdheight' OptionSet", function()
|
|
exec('tabnew | tabprev')
|
|
feed(':set ch=0')
|
|
screen:expect([[
|
|
{5: [No Name] }{24: [No Name] }{2: }{24:X}|
|
|
|
|
|
{1:~ }|*11
|
|
{16::}{15:set} {16:ch}{15:=}0^ |
|
|
]])
|
|
feed('<CR>')
|
|
exec('tabnext')
|
|
screen:expect([[
|
|
{24: [No Name] }{5: [No Name] }{2: }{24:X}|
|
|
^ |
|
|
{1:~ }|*11
|
|
{16::}{15:set} {16:ch}{15:=}0 |
|
|
]])
|
|
exec('tabnext')
|
|
screen:expect([[
|
|
{5: [No Name] }{24: [No Name] }{2: }{24:X}|
|
|
^ |
|
|
{1:~ }|*12
|
|
]])
|
|
n.assert_alive()
|
|
end)
|
|
|
|
it("redraw does not clear 'incsearch' highlight with conceal", function()
|
|
exec('call setline(1, ["foo", "foobar"]) | set conceallevel=1 concealcursor=c')
|
|
feed('/foo')
|
|
screen:expect([[
|
|
{10:foo} |
|
|
{2:foo}bar |
|
|
{1:~ }|*11
|
|
/foo^ |
|
|
]])
|
|
end)
|
|
|
|
it('block mode', function()
|
|
feed(':if 1<CR>')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*11
|
|
{16::}{15:if} {26:1} |
|
|
{16::} ^ |
|
|
]])
|
|
feed('echo "foo"')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*11
|
|
{16::}{15:if} {26:1} |
|
|
{16::} {15:echo} {26:"foo"}^ |
|
|
]])
|
|
feed('<CR>')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*9
|
|
{16::}{15:if} {26:1} |
|
|
{16::} {15:echo} {26:"foo"} |
|
|
foo |
|
|
{16::} ^ |
|
|
]])
|
|
feed([[echo input("foo\nbar:")<CR>]])
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*7
|
|
{16::}{15:if} {26:1} |
|
|
{16::} {15:echo} {26:"foo"} |
|
|
foo |
|
|
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
|
foo |
|
|
bar:^ |
|
|
]])
|
|
feed('baz')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*7
|
|
{16::}{15:if} {26:1} |
|
|
{16::} {15:echo} {26:"foo"} |
|
|
foo |
|
|
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
|
foo |
|
|
bar:baz^ |
|
|
]])
|
|
feed('<CR>')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*5
|
|
{16::}{15:if} {26:1} |
|
|
{16::} {15:echo} {26:"foo"} |
|
|
foo |
|
|
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
|
foo |
|
|
bar:baz |
|
|
baz |
|
|
{16::} ^ |
|
|
]])
|
|
feed('endif')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*5
|
|
{16::}{15:if} {26:1} |
|
|
{16::} {15:echo} {26:"foo"} |
|
|
foo |
|
|
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
|
|
foo |
|
|
bar:baz |
|
|
baz |
|
|
{16::} {15:endif}^ |
|
|
]])
|
|
feed('<CR>')
|
|
screen:expect([[
|
|
^ |
|
|
{1:~ }|*12
|
|
|
|
|
]])
|
|
end)
|
|
|
|
it('handles empty prompt', function()
|
|
feed(":call input('')<CR>")
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*12
|
|
^ |
|
|
]])
|
|
-- Message moved to dialog with empty prompt
|
|
feed("<CR>:echo 'foo' | call input('')<CR>")
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*10
|
|
{3: }|
|
|
foo |
|
|
^ |
|
|
]])
|
|
end)
|
|
|
|
it('highlights after deleting buffer', function()
|
|
feed(':sil %bw!<CR>:call foo()')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*12
|
|
{16::}{15:call} {25:foo}{16:()}^ |
|
|
]])
|
|
end)
|
|
|
|
it('can change cmdline buffer during textlock', function()
|
|
exec([[
|
|
func Foo(a, b)
|
|
redrawstatus!
|
|
endfunc
|
|
set wildoptions=pum findfunc=Foo wildmode=noselect:lastused,full
|
|
au CmdlineChanged * call wildtrigger()
|
|
]])
|
|
feed(':find ')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*12
|
|
{16::}{15:find} ^ |
|
|
]])
|
|
t.eq("E1514: 'findfunc' did not return a List type", n.eval('v:errmsg'))
|
|
end)
|
|
|
|
it('substitution match, empty message does not clear active cmdline', function()
|
|
exec('call setline(1, "foo")')
|
|
feed(':s/f')
|
|
screen:expect([[
|
|
{10:f}oo |
|
|
{1:~ }|*12
|
|
{16::}{15:s}{16:/f^ } |
|
|
]])
|
|
feed('<Esc>:foo')
|
|
screen:expect([[
|
|
foo |
|
|
{1:~ }|*12
|
|
{16::}{15:foo}^ |
|
|
]])
|
|
exec('echo')
|
|
screen:expect_unchanged(true)
|
|
end)
|
|
|
|
it('keeps the confirmation match highlighted with nohlsearch #41039', function()
|
|
exec('call setline(1, "test test") | set nohlsearch')
|
|
feed('/te<CR>')
|
|
screen:expect([[
|
|
test ^test |
|
|
{1:~ }|*12
|
|
/te |
|
|
]])
|
|
|
|
feed(':%s/te/t/gc<CR>')
|
|
screen:expect([[
|
|
{2:te}st test |
|
|
{1:~ }|*11
|
|
{6:replace with t? (y)es/(n)o/(a)ll/(q)uit/(l)ast/scroll}|
|
|
{6: up(^E)/down(^Y)}^ |
|
|
]])
|
|
end)
|
|
|
|
it('dialog position is adjusted for toggled non-pum wildmenu', function()
|
|
exec([[
|
|
set wildmode=list:full,full wildoptions-=pum
|
|
func Foo()
|
|
endf
|
|
func Fooo()
|
|
endf
|
|
]])
|
|
feed(':call Fo<C-Z>')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*8
|
|
{3: }|
|
|
Foo() Fooo() |
|
|
|
|
|
{101:Foo()}{3: Fooo() }|
|
|
{16::}{15:call} {25:Foo}{16:()}^ |
|
|
]])
|
|
feed('<BS><BS>')
|
|
exec('set wildoptions+=pum laststatus=2')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*9
|
|
{3: }|
|
|
Foo() Fooo() |
|
|
|
|
|
{16::}{15:call} Foo^ |
|
|
]])
|
|
feed('<C-Z>')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*9
|
|
{3: }|
|
|
Foo(){12: Foo() } |
|
|
{4: Fooo() } |
|
|
{16::}{15:call} {25:Foo}{16:()}^ |
|
|
]])
|
|
end)
|
|
|
|
it('updated after setcmdline() #38764', function()
|
|
-- Also check that command-preview is updated.
|
|
exec('call setline(1, "foo")')
|
|
feed(':%s/foo')
|
|
screen:expect([[
|
|
{10:foo} |
|
|
{1:~ }|*12
|
|
{16::}%{15:s}{16:/foo^ } |
|
|
]])
|
|
exec_lua(function()
|
|
_G.events = {}
|
|
vim.api.nvim_create_autocmd({ 'CmdlineChanged', 'CursorMovedC' }, {
|
|
callback = function(ev)
|
|
_G.events[ev.event] = (_G.events[ev.event] or 0) + 1
|
|
end,
|
|
})
|
|
end)
|
|
exec('call setcmdline("%s/fo")')
|
|
screen:expect([[
|
|
{10:fo}o |
|
|
{1:~ }|*12
|
|
{16::}%{15:s}{16:/fo^ } |
|
|
]])
|
|
t.eq({ CmdlineChanged = 1, CursorMovedC = 1 }, exec_lua('return _G.events'))
|
|
end)
|
|
|
|
it("no 'incsearch' recursion with 'verbose' regex message", function()
|
|
exec('set verbose=1')
|
|
feed([[:%s/.\{//}]])
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*9
|
|
{3: }|
|
|
Switching to backtracking RE engine for pattern: .\{ |*2
|
|
{16::}%{15:s}{16:/.\{//}^ } |
|
|
]])
|
|
end)
|
|
|
|
it('is empty after backspace', function()
|
|
feed(':')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*12
|
|
{16::}^ |
|
|
]])
|
|
|
|
feed('<BS>')
|
|
screen:expect([[
|
|
^ |
|
|
{1:~ }|*12
|
|
|
|
|
]])
|
|
end)
|
|
|
|
it('matchparen highlights', function()
|
|
exec('source $VIMRUNTIME/plugin/matchparen.lua')
|
|
feed(':call foo(bar())')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*12
|
|
{16::}{15:call} {25:foo}{102:(}{25:bar}{16:()}{102:)}^ |
|
|
]])
|
|
feed('<Left>')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*12
|
|
{16::}{15:call} {25:foo}{16:(}{25:bar}{102:()}{16:^)} |
|
|
]])
|
|
feed('<Right><BS><BS>')
|
|
screen:expect([[
|
|
|
|
|
{1:~ }|*12
|
|
{16::}{15:call} {25:foo}{16:(}{25:bar}{16:(}^ |
|
|
]])
|
|
end)
|
|
|
|
it("doesn't interfere with :$q", function()
|
|
exec('split b')
|
|
exec('wincmd J')
|
|
exec('wincmd p')
|
|
exec('$q') -- this would close a ui2 window, not the second visible window
|
|
|
|
local nwins = vim.fn.winnr('$')
|
|
assert(nwins == 1)
|
|
end)
|
|
end)
|
|
|
|
describe('cmdline2', function()
|
|
it('resizing during startup shows confirm prompt #36439', function()
|
|
clear({
|
|
args = {
|
|
'--clean',
|
|
'+lua require("vim._core.ui2").enable({})',
|
|
"+call feedkeys(':')",
|
|
},
|
|
})
|
|
local screen = Screen.new()
|
|
feed('call confirm("Ok?")<CR>')
|
|
screen:try_resize(screen._width + 1, screen._height)
|
|
screen:expect([[
|
|
|*10
|
|
{3: }|
|
|
|
|
|
{6:Ok?} |
|
|
{6:[O]k: }^ |
|
|
]])
|
|
-- And resizing the next event loop iteration also works.
|
|
feed('k')
|
|
screen:try_resize(screen._width, screen._height + 1)
|
|
screen:expect([[
|
|
|*11
|
|
{3: }|
|
|
|
|
|
{6:Ok?} |
|
|
{6:[O]k: }^ |
|
|
]])
|
|
end)
|
|
end)
|