Files
neovim/test/functional/ui/messages2_spec.lua
yilisharcs b9451dfd4c fix(ui2): emit FileType event after setting default pager options #36315
Problem: Setting a filetype before configuring default options for ui2
buffers (pager, cmd, ...) prevents users from setting their own options.

Solution: Call nvim_set_option_value after defaults are set.

Closes #36314

Co-authored-by: Luuk van Baal <luukvbaal@gmail.com>
2025-10-27 10:19:16 -07:00

442 lines
22 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 clear, command, exec_lua, feed = n.clear, n.command, n.exec_lua, n.feed
describe('messages2', function()
local screen
before_each(function()
clear()
screen = Screen.new()
screen:add_extra_attr_ids({
[100] = { foreground = Screen.colors.Magenta1, bold = true },
})
exec_lua(function()
require('vim._extui').enable({})
end)
end)
after_each(function()
-- Since vim._extui lasts until Nvim exits, there may be unfinished timers.
-- Close unfinished timers to avoid 2s delay on exit with ASAN or TSAN.
exec_lua(function()
vim.uv.walk(function(handle)
if not handle:is_closing() then
handle:close()
end
end)
end)
end)
it('multiline messages and pager', function()
command('echo "foo\nbar"')
screen:expect([[
^ |
{1:~ }|*10
{3:─────────────────────────────────────────────────────}|
foo |
bar |
]])
command('set ruler showcmd noshowmode')
feed('g<lt>')
screen:expect([[
|
{1:~ }|*9
{3:─────────────────────────────────────────────────────}|
fo^o |
bar |
1,3 All|
]])
-- Multiple messages in same event loop iteration are appended and shown in full.
feed([[q:echo "foo" | echo "bar\nbaz\n"->repeat(&lines)<CR>]])
screen:expect([[
^ |
{1:~ }|*5
{3:─────────────────────────────────────────────────────}|
foo |
bar |
baz |
bar |
baz |
bar |
baz [+23] |
]])
-- Any key press resizes the cmdline and updates the spill indicator.
feed('j')
screen:expect([[
^ |
{1:~ }|*12
foo [+29] 0,0-1 All|
]])
command('echo "foo"')
-- New message clears spill indicator.
screen:expect([[
^ |
{1:~ }|*12
foo 0,0-1 All|
]])
-- No error for ruler virt_text msg_row exceeding buffer length.
command([[map Q <cmd>echo "foo\nbar" <bar> ls<CR>]])
feed('Q')
screen:expect([[
^ |
{1:~ }|*8
{3:─────────────────────────────────────────────────────}|
foo |
bar |
|
1 %a "[No Name]" line 1 |
]])
feed('<C-L>')
screen:expect([[
^ |
{1:~ }|*12
0,0-1 All|
]])
-- edit_unputchar() does not clear already updated screen #34515.
feed('ix<Esc>dwi<C-r>')
screen:expect([[
{18:^"} |
{1:~ }|*12
^R 1,1 All|
]])
feed('-')
screen:expect([[
x^ |
{1:~ }|*12
1,2 All|
]])
end)
it('new buffer, window and options after closing a buffer', function()
command('set nomodifiable | echom "foo" | messages')
screen:expect([[
|
{1:~ }|*10
{3:─────────────────────────────────────────────────────}|
fo^o |
foo |
]])
command('bdelete | messages')
screen:expect_unchanged()
end)
it('screenclear and empty message clears messages', function()
command('echo "foo"')
screen:expect([[
^ |
{1:~ }|*12
foo |
]])
command('mode')
screen:expect([[
^ |
{1:~ }|*12
|
]])
command('echo "foo"')
screen:expect([[
^ |
{1:~ }|*12
foo |
]])
command('echo ""')
screen:expect([[
^ |
{1:~ }|*12
|
]])
command('set cmdheight=0')
command('echo "foo"')
screen:expect([[
^ |
{1:~ }|*10
{1:~ }|
{1:~ }|
{1:~ }{4:foo}|
]])
command('mode')
screen:expect([[
^ |
{1:~ }|*13
]])
-- But not with target='msg'
command('echo "foo"')
screen:expect([[
^ |
{1:~ }|*10
{1:~ }|
{1:~ }|
{1:~ }{4:foo}|
]])
command('echo ""')
screen:expect_unchanged()
-- Or a screen resize
screen:try_resize(screen._width, screen._height - 1)
screen:expect([[
^ |
{1:~ }|*9
{1:~ }|
{1:~ }|
{1:~ }{4:foo}|
]])
-- Moved up when opening cmdline
feed(':')
screen:expect([[
|
{1:~ }|*10
{1:~ }{4:foo}|
{16::}^ |
]])
-- Highlighter disabled when message is moved to cmdline #34884
feed([[echo "bar\n"->repeat(&lines)<CR>]])
screen:expect([[
^ |
{1:~ }|*4
{3:─────────────────────────────────────────────────────}|
foo |
bar |*5
bar [+8] |
]])
end)
it("deleting buffer restores 'buftype'", function()
feed(':%bdelete<CR>')
screen:expect([[
^ |
{1:~ }|*12
5 buffers deleted |
]])
-- Would trigger changed dialog if 'buftype' was not restored.
command('%bdelete')
screen:expect_unchanged()
end)
it('showmode does not overwrite important messages', function()
command('set readonly')
feed('i')
screen:expect([[
^ |
{1:~ }|*12
{19:W10: Warning: Changing a readonly file} |
]])
feed('<Esc>Qi')
screen:expect([[
^ |
{1:~ }|*12
{9:E354: Invalid register name: '^@'} |
]])
end)
it('hit-enter prompt does not error for invalid window #35095', function()
command('echo "foo\nbar"')
screen:expect([[
^ |
{1:~ }|*10
{3:─────────────────────────────────────────────────────}|
foo |
bar |
]])
feed('<C-w>o')
screen:expect([[
^ |
{1:~ }|*12
foo [+1] |
]])
end)
it('not restoring already open hit-enter-prompt config #35298', function()
command('echo "foo\nbar"')
screen:expect([[
^ |
{1:~ }|*10
{3:─────────────────────────────────────────────────────}|
foo |
bar |
]])
command('echo "foo\nbar"')
screen:expect_unchanged()
feed(':')
screen:expect([[
|
{1:~ }|*12
{16::}^ |
]])
end)
it('paging prompt dialog #35191', function()
screen:try_resize(71, screen._height)
local top = [[
|
{1:~ }|*4
{3:───────────────────────────────────────────────────────────────────────}|
0 |
1 |
2 |
3 |
4 |
5 |
6 [+93] |
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
]]
feed(':call inputlist(range(100))<CR>')
screen:expect(top)
feed('j')
screen:expect([[
|
{1:~ }|*4
{3:───────────────────────────────────────────────────────────────────────}|
1 [+1] |
2 |
3 |
4 |
5 |
6 |
7 [+92] |
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
]])
feed('k')
screen:expect(top)
feed('d')
screen:expect([[
|
{1:~ }|*4
{3:───────────────────────────────────────────────────────────────────────}|
3 [+3] |
4 |
5 |
6 |
7 |
8 |
9 [+90] |
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
]])
feed('u')
screen:expect(top)
feed('f')
screen:expect([[
|
{1:~ }|*4
{3:───────────────────────────────────────────────────────────────────────}|
5 [+5] |
6 |
7 |
8 |
9 |
10 |
11 [+88] |
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
]])
feed('b')
screen:expect(top)
feed('G')
screen:expect([[
|
{1:~ }|*4
{3:───────────────────────────────────────────────────────────────────────}|
93 [+93] |
94 |
95 |
96 |
97 |
98 |
99 |
Type number and <Enter> or click with the mouse (q or empty cancels): ^ |
]])
-- No scrolling beyond end of buffer #36114
feed('f')
screen:expect([[
|
{1:~ }|*3
{3:───────────────────────────────────────────────────────────────────────}|
93 [+93] |
94 |
95 |
96 |
97 |
98 |
99 |
Type number and <Enter> or click with the mouse (q or empty cancels): f|
^ |
]])
feed('<Backspace>g')
screen:expect(top)
end)
it('in cmdline_block mode', function()
feed(':if 1<CR>')
screen:expect([[
|
{1:~ }|*11
{16::}{15:if} {26:1} |
{16::} ^ |
]])
feed([[echo input("foo\nbar:")<CR>]])
screen:expect([[
|
{1:~ }|*9
:if 1 |
: echo input("foo\nbar:") |
foo |
bar:^ |
]])
feed('baz<CR>')
screen:expect([[
|
{1:~ }|*9
{16::}{15:if} {26:1} |
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
{15:baz} |
{16::} ^ |
]])
feed([[echo input("foo\nbar:")<CR>]])
screen:expect([[
|
{1:~ }|*7
:if 1 |
: echo input("foo\nbar:") |
baz |
: echo input("foo\nbar:") |
foo |
bar:^ |
]])
feed('<Esc>:endif')
screen:expect([[
|
{1:~ }|*8
{16::}{15:if} {26:1} |
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
{15:baz} |
{16::} {15:echo} {25:input}{16:(}{26:"foo\nbar:"}{16:)} |
{16::} {16::}{15:endif}^ |
]])
feed('<CR>')
screen:expect([[
^ |
{1:~ }|*12
|
]])
end)
it('FileType is fired after default options are set', function()
n.exec([[
let g:set = {}
au FileType pager set nowrap
au OptionSet * let g:set[expand('<amatch>')] = g:set->get(expand('<amatch>'), 0) + 1
echom 'foo'->repeat(&columns)
messages
]])
screen:expect([[
|
{1:~ }|*9
{3:─────────────────────────────────────────────────────}|
^foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo|
{1: }|
|
]])
t.eq({ filetype = 4 }, n.eval('g:set')) -- still fires for 'filetype'
end)
end)