diff options
Diffstat (limited to 'test')
29 files changed, 2647 insertions, 151 deletions
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 0e06e48a35..b10076c6da 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -318,6 +318,10 @@ describe('API', function() eq({false, 'Error executing lua: [string "<nvim>"]:1: '.. "attempt to call global 'bork' (a nil value)"}, meth_pcall(meths.execute_lua, 'bork()', {})) + + eq({false, 'Error executing lua: [string "<nvim>"]:1: '.. + "did\nthe\nfail"}, + meth_pcall(meths.execute_lua, 'error("did\\nthe\\nfail")', {})) end) end) @@ -1273,7 +1277,9 @@ describe('API', function() ext_wildmenu = false, ext_linegrid = screen._options.ext_linegrid or false, ext_multigrid = false, - ext_hlstate=false, + ext_hlstate = false, + ext_termcolors = false, + ext_messages = false, height = 4, rgb = true, width = 20, @@ -1303,4 +1309,84 @@ describe('API', function() eq({["ns-1"]=1, ["ns-2"]=2}, meths.get_namespaces()) end) end) + + describe('nvim_create_buf', function() + it('works', function() + eq({id=2}, meths.create_buf(true, false)) + eq({id=3}, meths.create_buf(false, false)) + eq(' 1 %a "[No Name]" line 1\n'.. + ' 2 "[No Name]" line 0', + meths.command_output("ls")) + -- current buffer didn't change + eq({id=1}, meths.get_current_buf()) + + local screen = Screen.new(20, 4) + screen:attach() + meths.buf_set_lines(2, 0, -1, true, {"some text"}) + meths.set_current_buf(2) + screen:expect([[ + ^some text | + {1:~ }| + {1:~ }| + | + ]], { + [1] = {bold = true, foreground = Screen.colors.Blue1}, + }) + end) + + it('can change buftype before visiting', function() + meths.set_option("hidden", false) + eq({id=2}, meths.create_buf(true, false)) + meths.buf_set_option(2, "buftype", "nofile") + meths.buf_set_lines(2, 0, -1, true, {"test text"}) + command("split | buffer 2") + eq({id=2}, meths.get_current_buf()) + -- if the buf_set_option("buftype") didn't work, this would error out. + command("close") + eq({id=1}, meths.get_current_buf()) + end) + + it('|scratch-buffer|', function() + eq({id=2}, meths.create_buf(false, true)) + eq({id=3}, meths.create_buf(true, true)) + eq({id=4}, meths.create_buf(true, true)) + local scratch_bufs = { 2, 3, 4 } + eq(' 1 %a "[No Name]" line 1\n'.. + ' 3 "[Scratch]" line 0\n'.. + ' 4 "[Scratch]" line 0', + meths.command_output("ls")) + -- current buffer didn't change + eq({id=1}, meths.get_current_buf()) + + local screen = Screen.new(20, 4) + screen:attach() + + -- + -- Editing a scratch-buffer does NOT change its properties. + -- + local edited_buf = 2 + meths.buf_set_lines(edited_buf, 0, -1, true, {"some text"}) + for _,b in ipairs(scratch_bufs) do + eq('nofile', meths.buf_get_option(b, 'buftype')) + eq('hide', meths.buf_get_option(b, 'bufhidden')) + eq(false, meths.buf_get_option(b, 'swapfile')) + end + + -- + -- Visiting a scratch-buffer DOES change its properties. + -- + meths.set_current_buf(edited_buf) + screen:expect([[ + ^some text | + {1:~ }| + {1:~ }| + | + ]], { + [1] = {bold = true, foreground = Screen.colors.Blue1}, + }) + eq('', meths.buf_get_option(edited_buf, 'buftype')) + eq('', meths.buf_get_option(edited_buf, 'bufhidden')) + eq(false, meths.buf_get_option(edited_buf, 'swapfile')) + end) + end) end) diff --git a/test/functional/autocmd/signal_spec.lua b/test/functional/autocmd/signal_spec.lua new file mode 100644 index 0000000000..719adeaf1b --- /dev/null +++ b/test/functional/autocmd/signal_spec.lua @@ -0,0 +1,38 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local funcs = helpers.funcs +local next_msg = helpers.next_msg + +if helpers.pending_win32(pending) then + -- Only applies to POSIX systems. + return +end + +local function posix_kill(signame, pid) + os.execute('kill -s '..signame..' -- '..pid..' >/dev/null') +end + +describe('autocmd Signal', function() + before_each(clear) + + it('matches *', function() + command('autocmd Signal * call rpcnotify(1, "foo")') + posix_kill('USR1', funcs.getpid()) + eq({'notification', 'foo', {}}, next_msg()) + end) + + it('matches SIGUSR1', function() + command('autocmd Signal SIGUSR1 call rpcnotify(1, "foo")') + posix_kill('USR1', funcs.getpid()) + eq({'notification', 'foo', {}}, next_msg()) + end) + + it('does not match unknown patterns', function() + command('autocmd Signal SIGUSR2 call rpcnotify(1, "foo")') + posix_kill('USR1', funcs.getpid()) + eq(nil, next_msg(500)) + end) +end) diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua index 124b9625c3..14f3c29fb7 100644 --- a/test/functional/eval/timer_spec.lua +++ b/test/functional/eval/timer_spec.lua @@ -4,6 +4,7 @@ local feed, eq, eval = helpers.feed, helpers.eq, helpers.eval local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run local clear, command, funcs = helpers.clear, helpers.command, helpers.funcs local curbufmeths = helpers.curbufmeths +local load_adjust = helpers.load_adjust describe('timers', function() before_each(function() @@ -19,14 +20,14 @@ describe('timers', function() it('works one-shot', function() command("call timer_start(50, 'MyHandler')") eq(0,eval("g:val")) - run(nil, nil, nil, 200) + run(nil, nil, nil, load_adjust(200)) eq(1,eval("g:val")) end) it('works one-shot when repeat=0', function() command("call timer_start(50, 'MyHandler', {'repeat': 0})") eq(0,eval("g:val")) - run(nil, nil, nil, 200) + run(nil, nil, nil, load_adjust(200)) eq(1,eval("g:val")) end) @@ -34,7 +35,7 @@ describe('timers', function() it('works with repeat two', function() command("call timer_start(50, 'MyHandler', {'repeat': 2})") eq(0,eval("g:val")) - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) eq(2,eval("g:val")) end) @@ -42,14 +43,14 @@ describe('timers', function() command("call timer_start(50, 'MyHandler', {'repeat': 2})") nvim_async("command", "sleep 10") eq(0,eval("g:val")) - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) eq(2,eval("g:val")) end) it('works with zero timeout', function() -- timer_start does still not invoke the callback immediately eq(0,eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]")) - run(nil, nil, nil, 400) + run(nil, nil, nil, load_adjust(400)) eq(1000,eval("g:val")) end) @@ -58,18 +59,18 @@ describe('timers', function() -- this also tests that remote requests works during sleep eval("timer_start(50, 'MyHandler', {'repeat': 2})") eq(0,eval("g:val")) - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) eq(2,eval("g:val")) end) it('are paused when event processing is disabled', function() command("call timer_start(50, 'MyHandler', {'repeat': -1})") - run(nil, nil, nil, 100) + run(nil, nil, nil, load_adjust(100)) local count = eval("g:val") -- shows two line error message and thus invokes the return prompt. -- if we start to allow event processing here, we need to change this test. feed(':throw "fatal error"<CR>') - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) feed("<cr>") local diff = eval("g:val") - count assert(0 <= diff and diff <= 4, @@ -79,7 +80,7 @@ describe('timers', function() it('are triggered in blocking getchar() call', function() command("call timer_start(50, 'MyHandler', {'repeat': -1})") nvim_async("command", "let g:c = getchar()") - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) feed("c") local count = eval("g:val") assert(count >= 3, 'expected count >= 3, got: '..tostring(count)) @@ -137,15 +138,16 @@ describe('timers', function() it('can be stopped', function() local t = eval("timer_start(50, 'MyHandler', {'repeat': -1})") eq(0,eval("g:val")) - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) funcs.timer_stop(t) local count = eval("g:val") - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) local count2 = eval("g:val") -- when count is eval:ed after timer_stop this should be non-racy eq(count, count2) - assert(3 <= count and count <= 7, - 'expected (3 <= count <= 7), got: '..tostring(count)) + assert((3 <= count and count <= load_adjust(7)), + string.format('expected (3 <= count <= %s), got: %s', + load_adjust(7), tostring(count))) end) it('can be stopped from the handler', function() @@ -161,7 +163,7 @@ describe('timers', function() ]]) command("call timer_start(50, 'MyHandler', {'repeat': -1})") eq(0,eval("g:val")) - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) eq(3,eval("g:val")) end) @@ -174,7 +176,7 @@ describe('timers', function() ]]) command("call timer_start(20, 'MyHandler', {'repeat': 3})") command("call timer_start(40, 'MyHandler2', {'repeat': 2})") - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) eq(3,eval("g:val")) eq(2,eval("g:val2")) end) @@ -189,7 +191,7 @@ describe('timers', function() endfunc ]]) command("call timer_start(5, 'MyHandler', {'repeat': 1})") - run(nil, nil, nil, 300) + run(nil, nil, nil, load_adjust(300)) eq(1,eval("g:val")) end) diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua index 2c0535acda..2309e949c0 100644 --- a/test/functional/ex_cmds/menu_spec.lua +++ b/test/functional/ex_cmds/menu_spec.lua @@ -63,25 +63,27 @@ describe('menu_get', function() before_each(function() clear() - command('nnoremenu &Test.Test inormal<ESC>') - command('inoremenu Test.Test insert') - command('vnoremenu Test.Test x') - command('cnoremenu Test.Test cmdmode') - command('menu Test.Nested.test level1') - command('menu Test.Nested.Nested2 level2') + command([=[ + nnoremenu &Test.Test inormal<ESC> + inoremenu Test.Test insert + vnoremenu Test.Test x + cnoremenu Test.Test cmdmode + menu Test.Nested.test level1 + menu Test.Nested.Nested2 level2 - command('nnoremenu <script> Export.Script p') - command('tmenu Export.Script This is the tooltip') - command('menu ]Export.hidden thisoneshouldbehidden') + nnoremenu <script> Export.Script p + tmenu Export.Script This is the tooltip + menu ]Export.hidden thisoneshouldbehidden - command('nnoremenu Edit.Paste p') - command('cnoremenu Edit.Paste <C-R>"') + nnoremenu Edit.Paste p + cnoremenu Edit.Paste <C-R>" + ]=]) end) it("path='', modes='a'", function() local m = funcs.menu_get("","a"); -- HINT: To print the expected table and regenerate the tests: - -- print(require('pl.pretty').dump(m)) + -- print(require('inspect')(m)) local expected = { { shortcut = "T", @@ -306,10 +308,13 @@ describe('menu_get', function() eq(expected, m) end) - it('matching path, default modes', function() + it('matching path, all modes', function() local m = funcs.menu_get("Export", "a") - local expected = { - { + local expected = { { + hidden = 0, + name = "Export", + priority = 500, + submenus = { { tooltip = "This is the tooltip", hidden = 0, name = "Script", @@ -323,8 +328,8 @@ describe('menu_get', function() silent = 0 } } - } - } + } } + } } eq(expected, m) end) @@ -349,8 +354,6 @@ describe('menu_get', function() name = "Test", hidden = 0 }, - { - } }, priority = 500, name = "Test" @@ -363,14 +366,22 @@ describe('menu_get', function() local m = funcs.menu_get("Test","i") local expected = { { - mappings = { - i = { - sid = 1, - noremap = 1, - enabled = 1, - rhs = "insert", - silent = 0 - } + shortcut = "T", + submenus = { + { + mappings = { + i = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "insert", + silent = 0 + }, + }, + priority = 500, + name = "Test", + hidden = 0 + }, }, priority = 500, name = "Test", diff --git a/test/functional/fixtures/tty-test.c b/test/functional/fixtures/tty-test.c index 5f1f5cb91c..e2a78a594b 100644 --- a/test/functional/fixtures/tty-test.c +++ b/test/functional/fixtures/tty-test.c @@ -20,6 +20,7 @@ uv_tty_t tty; uv_tty_t tty_out; +bool owns_tty(void); // silence -Wmissing-prototypes bool owns_tty(void) { #ifdef _WIN32 diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 851f3e720e..3e72ba6f98 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,4 +1,3 @@ -require('vim.compat') require('coxpcall') local luv = require('luv') local lfs = require('lfs') @@ -679,6 +678,44 @@ local function alter_slashes(obj) end end +local function compute_load_factor() + local timeout = 200 + local times = {} + + clear() + + for _ = 1, 5 do + source([[ + let g:val = 0 + call timer_start(200, {-> nvim_set_var('val', 1)}) + let start = reltime() + while 1 + sleep 10m + if g:val == 1 + let g:waited_in_ms = float2nr(reltimefloat(reltime(start)) * 1000) + break + endif + endwhile + ]]) + table.insert(times, nvim_eval('g:waited_in_ms')) + end + + session:close() + session = nil + + local longest = math.max(unpack(times)) + local factor = (longest + 50.0) / timeout + + return factor +end + +-- Compute load factor only once. +local load_factor = compute_load_factor() + +local function load_adjust(num) + return math.ceil(num * load_factor) +end + local module = { NIL = mpack.NIL, alter_slashes = alter_slashes, @@ -720,6 +757,7 @@ local module = { meths = meths, missing_provider = missing_provider, mkdir = lfs.mkdir, + load_adjust = load_adjust, near = near, neq = neq, new_pipename = new_pipename, diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 017ee55729..26dcbe0534 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -1,13 +1,17 @@ -- Test suite for checking :lua* commands local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local eq = helpers.eq local NIL = helpers.NIL +local eval = helpers.eval +local feed = helpers.feed local clear = helpers.clear local meths = helpers.meths local funcs = helpers.funcs local source = helpers.source local dedent = helpers.dedent +local command = helpers.command local exc_exec = helpers.exc_exec local write_file = helpers.write_file local redir_exec = helpers.redir_exec @@ -76,6 +80,64 @@ describe(':lua command', function() eq('', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s"})'):format(s))) eq({'', s}, curbufmeths.get_lines(0, -1, false)) end) + + it('can show multiline error messages', function() + local screen = Screen.new(50,10) + screen:attach() + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + + feed(':lua error("fail\\nmuch error\\nsuch details")<cr>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E5105: Error while calling lua chunk: [string "<Vi}| + {3:mL compiled string>"]:1: fail} | + {3:much error} | + {3:such details} | + {4:Press ENTER or type command to continue}^ | + ]]) + feed('<cr>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + eq('E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: fail\nmuch error\nsuch details', eval('v:errmsg')) + + local status, err = pcall(command,'lua error("some error\\nin a\\nAPI command")') + local expected = 'Vim(lua):E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: some error\nin a\nAPI command' + eq(false, status) + eq(expected, string.sub(err, -string.len(expected))) + + feed(':messages<cr>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E5105: Error while calling lua chunk: [string "<Vi}| + {3:mL compiled string>"]:1: fail} | + {3:much error} | + {3:such details} | + {4:Press ENTER or type command to continue}^ | + ]]) + end) end) describe(':luado command', function() diff --git a/test/functional/options/fillchars_spec.lua b/test/functional/options/chars_spec.lua index 99177a11b4..1330c29e61 100644 --- a/test/functional/options/fillchars_spec.lua +++ b/test/functional/options/chars_spec.lua @@ -4,6 +4,8 @@ local clear, command = helpers.clear, helpers.command local eval = helpers.eval local eq = helpers.eq local exc_exec = helpers.exc_exec +local insert = helpers.insert +local feed = helpers.feed describe("'fillchars'", function() local screen @@ -69,5 +71,51 @@ describe("'fillchars'", function() shouldfail('eob:xy') -- two ascii chars shouldfail('eob:\255', 'eob:<ff>') -- invalid UTF-8 end) + it('is local to window', function() + clear() + screen = Screen.new(50, 5) + screen:attach() + insert("foo\nbar") + command('set laststatus=0') + command('1,2fold') + command('vsplit') + command('set fillchars=fold:x') + screen:expect([[ + ^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: foo·······| + ~ │~ | + ~ │~ | + ~ │~ | + | + ]]) + end) + end) +end) + +describe("'listchars'", function() + local screen + + before_each(function() + clear() + screen = Screen.new(50, 5) + screen:attach() + end) + + after_each(function() + screen:detach() + end) + + it('is local to window', function() + feed('i<tab><tab><tab><esc>') + command('set laststatus=0') + command('set list listchars=tab:<->') + command('vsplit') + command('set listchars&') + screen:expect([[ + > > ^> │<------><------><------>| + ~ │~ | + ~ │~ | + ~ │~ | + | + ]]) end) end) diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua index fb0559054d..88e554c86f 100644 --- a/test/functional/options/num_options_spec.lua +++ b/test/functional/options/num_options_spec.lua @@ -32,9 +32,9 @@ describe(':setlocal', function() eq(0, meths.get_option('iminsert')) feed_command('setlocal iminsert=1') eq(0, meths.get_option('iminsert')) - eq(0, meths.get_option('imsearch')) + eq(-1, meths.get_option('imsearch')) feed_command('setlocal imsearch=1') - eq(0, meths.get_option('imsearch')) + eq(-1, meths.get_option('imsearch')) end) end) diff --git a/test/functional/terminal/altscreen_spec.lua b/test/functional/terminal/altscreen_spec.lua index 4526037808..155a156d15 100644 --- a/test/functional/terminal/altscreen_spec.lua +++ b/test/functional/terminal/altscreen_spec.lua @@ -8,7 +8,7 @@ local exit_altscreen = thelpers.exit_altscreen if helpers.pending_win32(pending) then return end -describe('terminal altscreen', function() +describe(':terminal altscreen', function() local screen before_each(function() diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 4d6b125f9f..e598c325a8 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -6,7 +6,7 @@ local eval, feed_command, source = helpers.eval, helpers.feed_command, helpers.s local eq, neq = helpers.eq, helpers.neq local write_file = helpers.write_file -describe('terminal buffer', function() +describe(':terminal buffer', function() local screen before_each(function() diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua index d942723d02..ef12438ecc 100644 --- a/test/functional/terminal/cursor_spec.lua +++ b/test/functional/terminal/cursor_spec.lua @@ -7,7 +7,7 @@ local feed_command = helpers.feed_command local hide_cursor = thelpers.hide_cursor local show_cursor = thelpers.show_cursor -describe('terminal cursor', function() +describe(':terminal cursor', function() local screen before_each(function() diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua index 7de0152de0..18f0b9e4c1 100644 --- a/test/functional/terminal/helpers.lua +++ b/test/functional/terminal/helpers.lua @@ -33,7 +33,7 @@ local function disable_mouse() feed_termcode('[?1002l') end local default_command = '["'..nvim_dir..'/tty-test'..'"]' -local function screen_setup(extra_rows, command, cols) +local function screen_setup(extra_rows, command, cols, opts) extra_rows = extra_rows and extra_rows or 0 command = command and command or default_command cols = cols and cols or 50 @@ -55,7 +55,7 @@ local function screen_setup(extra_rows, command, cols) [10] = {foreground = 121}, -- "Press ENTER" in embedded :terminal session. }) - screen:attach({rgb=false}) + screen:attach(opts or {rgb=false}) feed_command('enew | call termopen('..command..')') nvim('input', '<CR>') @@ -69,7 +69,7 @@ local function screen_setup(extra_rows, command, cols) -- tty-test puts the terminal into raw mode and echoes input. Tests work by -- feeding termcodes to control the display and asserting by screen:expect. - if command == default_command then + if command == default_command and opts == nil then -- Wait for "tty ready" to be printed before each test or the terminal may -- still be in canonical mode (will echo characters for example). local empty_line = (' '):rep(cols) diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index f33959c58d..9579e0ea0b 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -5,7 +5,7 @@ local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim local nvim_dir, command = helpers.nvim_dir, helpers.command local eq, eval = helpers.eq, helpers.eval -describe('terminal window highlighting', function() +describe(':terminal window highlighting', function() local screen before_each(function() diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index 263a5ce79d..64f437f206 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -4,7 +4,7 @@ local clear, eq, eval = helpers.clear, helpers.eq, helpers.eval local feed, nvim = helpers.feed, helpers.nvim local feed_data = thelpers.feed_data -describe('terminal mouse', function() +describe(':terminal mouse', function() local screen before_each(function() @@ -108,41 +108,42 @@ describe('terminal mouse', function() ]]) feed(':enew | set number<cr>') screen:expect([[ - {7: 1 }^ │line28 | - {4:~ }│line29 | + {7: 1 }^ │line29 | {4:~ }│line30 | {4:~ }│rows: 5, cols: 25 | + {4:~ }│rows: 5, cols: 24 | {4:~ }│{2: } | ========== ========== | :enew | set number | ]]) feed('30iline\n<esc>') screen:expect([[ - {7: 27 }line │line28 | - {7: 28 }line │line29 | - {7: 29 }line │line30 | - {7: 30 }line │rows: 5, cols: 25 | + {7: 27 }line │line29 | + {7: 28 }line │line30 | + {7: 29 }line │rows: 5, cols: 25 | + {7: 30 }line │rows: 5, cols: 24 | {7: 31 }^ │{2: } | ========== ========== | | ]]) feed('<c-w>li') screen:expect([[ - {7: 27 }line │line28 | - {7: 28 }line │line29 | - {7: 29 }line │line30 | - {7: 30 }line │rows: 5, cols: 25 | + {7: 27 }line │line29 | + {7: 28 }line │line30 | + {7: 29 }line │rows: 5, cols: 25 | + {7: 30 }line │rows: 5, cols: 24 | {7: 31 } │{1: } | ========== ========== | {3:-- TERMINAL --} | ]]) + -- enabling mouse won't affect interaction with other windows thelpers.enable_mouse() thelpers.feed_data('mouse enabled\n') screen:expect([[ - {7: 27 }line │line29 | - {7: 28 }line │line30 | - {7: 29 }line │rows: 5, cols: 25 | + {7: 27 }line │line30 | + {7: 28 }line │rows: 5, cols: 25 | + {7: 29 }line │rows: 5, cols: 24 | {7: 30 }line │mouse enabled | {7: 31 } │{1: } | ========== ========== | @@ -153,9 +154,9 @@ describe('terminal mouse', function() it('wont lose focus if another window is scrolled', function() feed('<ScrollWheelUp><0,0><ScrollWheelUp><0,0>') screen:expect([[ - {7: 21 }line │line29 | - {7: 22 }line │line30 | - {7: 23 }line │rows: 5, cols: 25 | + {7: 21 }line │line30 | + {7: 22 }line │rows: 5, cols: 25 | + {7: 23 }line │rows: 5, cols: 24 | {7: 24 }line │mouse enabled | {7: 25 }line │{1: } | ========== ========== | @@ -163,9 +164,9 @@ describe('terminal mouse', function() ]]) feed('<S-ScrollWheelDown><0,0>') screen:expect([[ - {7: 26 }line │line29 | - {7: 27 }line │line30 | - {7: 28 }line │rows: 5, cols: 25 | + {7: 26 }line │line30 | + {7: 27 }line │rows: 5, cols: 25 | + {7: 28 }line │rows: 5, cols: 24 | {7: 29 }line │mouse enabled | {7: 30 }line │{1: } | ========== ========== | @@ -176,15 +177,49 @@ describe('terminal mouse', function() it('will lose focus if another window is clicked', function() feed('<LeftMouse><5,1>') screen:expect([[ - {7: 27 }line │line29 | - {7: 28 }l^ine │line30 | - {7: 29 }line │rows: 5, cols: 25 | + {7: 27 }line │line30 | + {7: 28 }l^ine │rows: 5, cols: 25 | + {7: 29 }line │rows: 5, cols: 24 | {7: 30 }line │mouse enabled | {7: 31 } │{2: } | ========== ========== | | ]]) end) + + it('handles terminal size when switching buffers', function() + nvim('set_option', 'hidden', true) + feed('<c-\\><c-n><c-w><c-w>') + screen:expect([[ + {7: 27 }line │line30 | + {7: 28 }line │rows: 5, cols: 25 | + {7: 29 }line │rows: 5, cols: 24 | + {7: 30 }line │mouse enabled | + {7: 31 }^ │{2: } | + ========== ========== | + | + ]]) + feed(':bn<cr>') + screen:expect([[ + rows: 5, cols: 25 │rows: 5, cols: 25 | + rows: 5, cols: 24 │rows: 5, cols: 24 | + mouse enabled │mouse enabled | + rows: 5, cols: 25 │rows: 5, cols: 25 | + {2:^ } │{2: } | + ========== ========== | + :bn | + ]]) + feed(':bn<cr>') + screen:expect([[ + {7: 27 }line │rows: 5, cols: 24 | + {7: 28 }line │mouse enabled | + {7: 29 }line │rows: 5, cols: 25 | + {7: 30 }line │rows: 5, cols: 24 | + {7: 31 }^ │{2: } | + ========== ========== | + :bn | + ]]) + end) end) end) end) diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 1c97441213..75bb89a1ab 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -10,9 +10,10 @@ local wait = helpers.wait local retry = helpers.retry local curbufmeths = helpers.curbufmeths local nvim = helpers.nvim +local expect_err = helpers.expect_err local feed_data = thelpers.feed_data -describe('terminal scrollback', function() +describe(':terminal scrollback', function() local screen before_each(function() @@ -344,7 +345,7 @@ describe('terminal scrollback', function() end) end) -describe('terminal prints more lines than the screen height and exits', function() +describe(':terminal prints more lines than the screen height and exits', function() it('will push extra lines to scrollback', function() clear() local screen = Screen.new(30, 7) @@ -460,20 +461,15 @@ describe("'scrollback' option", function() screen:detach() end) - it('defaults to 10000 in terminal buffers', function() + it('defaults to 10000 in :terminal buffers', function() set_fake_shell() command('terminal') eq(10000, curbufmeths.get_option('scrollback')) end) it('error if set to invalid value', function() - local status, rv = pcall(command, 'set scrollback=-2') - eq(false, status) -- assert failure - eq('E474:', string.match(rv, "E%d*:")) - - status, rv = pcall(command, 'set scrollback=100001') - eq(false, status) -- assert failure - eq('E474:', string.match(rv, "E%d*:")) + expect_err('E474:', command, 'set scrollback=-2') + expect_err('E474:', command, 'set scrollback=100001') end) it('defaults to -1 on normal buffers', function() @@ -481,25 +477,41 @@ describe("'scrollback' option", function() eq(-1, curbufmeths.get_option('scrollback')) end) - it(':setlocal in a normal buffer is an error', function() - command('new') + it(':setlocal in a :terminal buffer', function() + set_fake_shell() - -- :setlocal to -1 is NOT an error. - feed_command('setlocal scrollback=-1') - eq(nil, string.match(eval("v:errmsg"), "E%d*:")) - feed('<CR>') + -- _Global_ scrollback=-1 defaults :terminal to 10_000. + command('setglobal scrollback=-1') + command('terminal') + eq(10000, curbufmeths.get_option('scrollback')) + + -- _Local_ scrollback=-1 in :terminal forces the _maximum_. + command('setlocal scrollback=-1') + retry(nil, nil, function() -- Fixup happens on refresh, not immediately. + eq(100000, curbufmeths.get_option('scrollback')) + end) - -- :setlocal to anything except -1 is an error. - feed_command('setlocal scrollback=42') - feed('<CR>') - eq('E474:', string.match(eval("v:errmsg"), "E%d*:")) + -- _Local_ scrollback=-1 during TermOpen forces the maximum. #9605 + command('setglobal scrollback=-1') + command('autocmd TermOpen * setlocal scrollback=-1') + command('terminal') + eq(100000, curbufmeths.get_option('scrollback')) + end) + + it(':setlocal in a normal buffer', function() + command('new') + -- :setlocal to -1. + command('setlocal scrollback=-1') eq(-1, curbufmeths.get_option('scrollback')) + -- :setlocal to anything except -1. Currently, this just has no effect. + command('setlocal scrollback=42') + eq(42, curbufmeths.get_option('scrollback')) end) it(':set updates local value and global default', function() set_fake_shell() - command('set scrollback=42') -- set global and (attempt) local - eq(-1, curbufmeths.get_option('scrollback')) -- normal buffer: -1 + command('set scrollback=42') -- set global value + eq(42, curbufmeths.get_option('scrollback')) command('terminal') eq(42, curbufmeths.get_option('scrollback')) -- inherits global default command('setlocal scrollback=99') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 1bc1334a6a..70356b7e2d 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -256,13 +256,13 @@ describe('TUI', function() end) it('shows up in nvim_list_uis', function() - feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(v))})\013') + feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(filter(v, {k,v -> k[:3] !=# "ext_" })))})\013') screen:expect([=[ - [[['ext_cmdline', v:false], ['ext_hlstate', v:fals| - e], ['ext_linegrid', v:true], ['ext_multigrid', v:| - false], ['ext_popupmenu', v:false], ['ext_tabline'| - , v:false], ['ext_wildmenu', v:false], ['height', | - 6], ['rgb', v:false], ['width', 50]]] | + | + {4:~ }| + {5: }| + [[['height', 6], ['rgb', v:false], ['width', 50]]]| + | {10:Press ENTER or type command to continue}{1: } | {3:-- TERMINAL --} | ]=]) diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index 842a81872e..4f62c75433 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -1,10 +1,15 @@ local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') +local feed_data = thelpers.feed_data local feed, clear = helpers.feed, helpers.clear local wait = helpers.wait local iswin = helpers.iswin +local command = helpers.command +local retry = helpers.retry +local eq = helpers.eq +local eval = helpers.eval -describe('terminal window', function() +describe(':terminal window', function() local screen before_each(function() @@ -12,6 +17,18 @@ describe('terminal window', function() screen = thelpers.screen_setup() end) + it('sets topline correctly #8556', function() + -- Test has hardcoded assumptions of dimensions. + eq(7, eval('&lines')) + feed_data('\n\n\n') -- Add blank lines. + -- Terminal/shell contents must exceed the height of this window. + command('topleft 1split') + eq('terminal', eval('&buftype')) + feed([[i<cr>]]) + -- Check topline _while_ in terminal-mode. + retry(nil, nil, function() eq(6, eval('winsaveview()["topline"]')) end) + end) + describe("with 'number'", function() it('wraps text', function() feed([[<C-\><C-N>]]) @@ -25,7 +42,7 @@ describe('terminal window', function() {7:6 } | {3:-- TERMINAL --} | ]]) - thelpers.feed_data({'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}) + feed_data({'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}) screen:expect([[ {7:1 }tty ready | {7:2 }rows: 6, cols: 48 | @@ -52,7 +69,7 @@ describe('terminal window', function() {7: 6 } | {3:-- TERMINAL --} | ]]) - thelpers.feed_data({' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}) + feed_data({' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}) screen:expect([[ {7: 1 }tty ready | {7: 2 }rows: 6, cols: 48 | @@ -96,7 +113,7 @@ describe('terminal window', function() describe('with fold set', function() before_each(function() feed([[<C-\><C-N>:set foldenable foldmethod=manual<CR>i]]) - thelpers.feed_data({'line1', 'line2', 'line3', 'line4', ''}) + feed_data({'line1', 'line2', 'line3', 'line4', ''}) screen:expect([[ tty ready | line1 | @@ -124,3 +141,101 @@ describe('terminal window', function() end) end) +describe(':terminal with multigrid', function() + local screen + + before_each(function() + clear() + screen = thelpers.screen_setup(0,nil,50,{ext_multigrid=true}) + end) + + it('resizes to requested size', function() + screen:expect([[ + ## grid 1 + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + {3:-- TERMINAL --} | + ## grid 2 + tty ready | + {1: } | + | + | + | + | + ]]) + + screen:try_resize_grid(2, 20, 10) + if iswin() then + screen:expect{any="rows: 10, cols: 20"} + else + screen:expect([[ + ## grid 1 + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + {3:-- TERMINAL --} | + ## grid 2 + tty ready | + rows: 10, cols: 20 | + {1: } | + | + | + | + | + | + | + | + ]]) + end + + screen:try_resize_grid(2, 70, 3) + if iswin() then + screen:expect{any="rows: 3, cols: 70"} + else + screen:expect([[ + ## grid 1 + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + {3:-- TERMINAL --} | + ## grid 2 + rows: 10, cols: 20 | + rows: 3, cols: 70 | + {1: } | + ]]) + end + + screen:try_resize_grid(2, 0, 0) + if iswin() then + screen:expect{any="rows: 6, cols: 50"} + else + screen:expect([[ + ## grid 1 + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + [2:--------------------------------------------------]| + {3:-- TERMINAL --} | + ## grid 2 + tty ready | + rows: 10, cols: 20 | + rows: 3, cols: 70 | + rows: 6, cols: 50 | + {1: } | + | + ]]) + end + end) +end) diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua index fecffe3295..f3d0b45d09 100644 --- a/test/functional/terminal/window_split_tab_spec.lua +++ b/test/functional/terminal/window_split_tab_spec.lua @@ -9,7 +9,7 @@ local eval = helpers.eval local iswin = helpers.iswin local retry = helpers.retry -describe('terminal', function() +describe(':terminal', function() local screen before_each(function() diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 3228d6b7fc..536264019c 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -1151,6 +1151,39 @@ describe(":substitute, inccommand=split", function() eq("split", eval("&inccommand")) end) + it("deactivates if 'foldexpr' is slow #9557", function() + insert([[ + a + a + a + a + a + a + a + a + ]]) + source([[ + function! Slowfold(lnum) + sleep 5m + return a:lnum % 3 + endfun + ]]) + command('set redrawtime=1 inccommand=split') + command('set foldmethod=expr foldexpr=Slowfold(v:lnum)') + feed(':%s/a/bcdef') + + -- Assert that 'inccommand' is DISABLED in cmdline mode. + retry(nil, nil, function() + eq('', eval('&inccommand')) + end) + + -- Assert that 'inccommand' is again ENABLED after leaving cmdline mode. + feed([[<C-\><C-N>]]) + retry(nil, nil, function() + eq('split', eval('&inccommand')) + end) + end) + it("clears preview if non-previewable command is edited #5585", function() -- Put a non-previewable command in history. feed_command("echo 'foo'") diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua new file mode 100644 index 0000000000..388c6b3e95 --- /dev/null +++ b/test/functional/ui/messages_spec.lua @@ -0,0 +1,632 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear, feed = helpers.clear, helpers.feed +local eval = helpers.eval +local eq = helpers.eq +local command = helpers.command + + +describe('ui/ext_messages', function() + local screen + + before_each(function() + clear() + screen = Screen.new(25, 5) + screen:attach({rgb=true, ext_messages=true, ext_popupmenu=true}) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [3] = {bold = true}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [5] = {foreground = Screen.colors.Blue1}, + [6] = {bold = true, reverse = true}, + }) + end) + + it('supports :echoerr', function() + feed(':echoerr "raa"<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{"raa", 2}}, + kind = "echoerr", + }}} + + -- cmdline in a later input cycle clears error message + feed(':') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], cmdline={{ + firstc = ":", + content = {{ "" }}, + pos = 0, + }}} + + + feed('echoerr "bork" | echoerr "fail"<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "bork", 2 }}, + kind = "echoerr" + }, { + content = {{ "fail", 2 }}, + kind = "echoerr" + }, { + content = {{ "Press ENTER or type command to continue", 4 }}, + kind = "return_prompt" + }}} + + feed(':echoerr "extrafail"<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = { { "bork", 2 } }, + kind = "echoerr" + }, { + content = { { "fail", 2 } }, + kind = "echoerr" + }, { + content = { { "extrafail", 2 } }, + kind = "echoerr" + }, { + content = { { "Press ENTER or type command to continue", 4 } }, + kind = "return_prompt" + }}} + + feed('<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + + -- cmdline without interleaving wait/display keeps the error message + feed(':echoerr "problem" | let x = input("foo> ")<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "problem", 2 }}, + kind = "echoerr" + }}, cmdline={{ + prompt = "foo> ", + content = {{ "" }}, + pos = 0, + }}} + + feed('solution<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + eq('solution', eval('x')) + + feed(":messages<cr>") + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={ + {kind="echoerr", content={{"raa", 2}}}, + {kind="echoerr", content={{"bork", 2}}}, + {kind="echoerr", content={{"fail", 2}}}, + {kind="echoerr", content={{"extrafail", 2}}}, + {kind="echoerr", content={{"problem", 2}}} + }} + end) + + it('supports showmode', function() + command('imap <f2> <cmd>echomsg "stuff"<cr>') + feed('i') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], showmode={{"-- INSERT --", 3}}} + + feed('alphpabet<cr>alphanum<cr>') + screen:expect{grid=[[ + alphpabet | + alphanum | + ^ | + {1:~ }| + {1:~ }| + ]], showmode={ { "-- INSERT --", 3 } }} + + feed('<c-x>') + screen:expect{grid=[[ + alphpabet | + alphanum | + ^ | + {1:~ }| + {1:~ }| + ]], showmode={ { "-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)", 3 } }} + + feed('<c-p>') + screen:expect{grid=[[ + alphpabet | + alphanum | + alphanum^ | + {1:~ }| + {1:~ }| + ]], popupmenu={ + anchor = { 2, 0 }, + items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, + pos = 1 + }, showmode={ { "-- Keyword Local completion (^N^P) ", 3 }, { "match 1 of 2", 4 } }} + + -- echomsg and showmode don't overwrite each other, this is the same + -- as the TUI behavior with cmdheight=2 or larger. + feed('<f2>') + screen:expect{grid=[[ + alphpabet | + alphanum | + alphanum^ | + {1:~ }| + {1:~ }| + ]], popupmenu={ + anchor = { 2, 0 }, + items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, + pos = 1 + }, messages={ { + content = { { "stuff" } }, + kind = "echomsg" + } }, showmode={ { "-- Keyword Local completion (^N^P) ", 3 }, { "match 1 of 2", 4 } }} + + feed('<c-p>') + screen:expect{grid=[[ + alphpabet | + alphanum | + alphpabet^ | + {1:~ }| + {1:~ }| + ]], popupmenu={ + anchor = { 2, 0 }, + items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, + pos = 0 + }, messages={ { + content = { { "stuff" } }, + kind = "echomsg" + } }, showmode={ { "-- Keyword Local completion (^N^P) ", 3 }, { "match 2 of 2", 4 } }} + + feed("<esc>:messages<cr>") + screen:expect{grid=[[ + alphpabet | + alphanum | + alphpabe^t | + {1:~ }| + {1:~ }| + ]], messages={ + {kind="echomsg", content={{"stuff"}}}, + }} + end) + + it('supports showmode with recording message', function() + feed('qq') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], showmode={ { "recording @q", 3 } }} + + feed('i') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], showmode={ { "-- INSERT --recording @q", 3 } }} + + feed('<esc>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], showmode={ { "recording @q", 3 } }} + + feed('q') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + end) + + it('shows recording message with noshowmode', function() + command("set noshowmode") + feed('qq') + -- also check mode to avoid immediate success + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], showmode={ { "recording @q", 3 } }, mode="normal"} + + feed('i') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], showmode={ { "recording @q", 3 } }, mode="insert"} + + feed('<esc>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], showmode={ { "recording @q", 3 } }, mode="normal"} + + feed('q') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], mode="normal"} + end) + + it('supports showcmd and ruler', function() + command('set showcmd ruler') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], ruler={ { "0,0-1 All" } }} + feed('i') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], showmode={ { "-- INSERT --", 3 } }, ruler={ { "0,1 All" } }} + feed('abcde<cr>12345<esc>') + screen:expect{grid=[[ + abcde | + 1234^5 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], ruler={ { "2,5 All" } }} + feed('d') + screen:expect{grid=[[ + abcde | + 1234^5 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], showcmd={ { "d" } }, ruler={ { "2,5 All" } }} + feed('<esc>^') + screen:expect{grid=[[ + abcde | + ^12345 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], ruler={ { "2,1 All" } }} + feed('d') + screen:expect{grid=[[ + abcde | + ^12345 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], showcmd={ { "d" } }, ruler={ { "2,1 All" } }} + feed('i') + screen:expect{grid=[[ + abcde | + ^12345 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], showcmd={ { "di" } }, ruler={ { "2,1 All" } }} + feed('w') + screen:expect{grid=[[ + abcde | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + ]], ruler={ { "2,0-1 All" } }} + + -- when ruler is part of statusline it is not externalized. + -- this will be added as part of future ext_statusline support + command("set laststatus=2") + screen:expect([[ + abcde | + ^ | + {1:~ }| + {1:~ }| + {6:<o Name] [+] 2,0-1 All}| + ]]) + end) + + it('keeps history of message of different kinds', function() + feed(':echomsg "howdy"<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "howdy" }}, kind = "echomsg"} + }} + + -- always test a message without kind. If this one gets promoted to a + -- category, add a new message without kind. + feed('<c-c>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "Type :qa! and press <Enter> to abandon all changes and exit Nvim" }}, + kind = ""} + }} + + feed(':echoerr "bork"<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "bork", 2 }}, kind = "echoerr"} + }} + + feed(':echo "xyz"<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "xyz" }}, kind = "echo"} + }} + + feed(':call nosuchfunction()<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{ "E117: Unknown function: nosuchfunction", 2 }}, + kind = "emsg"} + }} + + feed(':messages<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={ + {kind="echomsg", content={{"howdy"}}}, + {kind="", content={{"Type :qa! and press <Enter> to abandon all changes and exit Nvim"}}}, + {kind="echoerr", content={{"bork", 2}}}, + {kind="emsg", content={{"E117: Unknown function: nosuchfunction", 2}}} + }} + end) + + it('implies ext_cmdline and ignores cmdheight', function() + eq(0, eval('&cmdheight')) + feed(':set cmdheight=1') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], cmdline={{ + content = { { "set cmdheight=1" } }, + firstc = ":", + pos = 15 } + }} + + feed('<cr>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + eq(0, eval('&cmdheight')) + + -- normally this would be an error + feed(':set cmdheight=0') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], cmdline={{ + content = { { "set cmdheight=0" } }, + firstc = ":", + pos = 15 } + }} + feed('<cr>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + eq(0, eval('&cmdheight')) + end) + + it('supports multiline messages', function() + feed(':lua error("such\\nmultiline\\nerror")<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{'E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: such\nmultiline\nerror', 2}}, + kind = "emsg" + }}} + end) +end) + +describe('ui/ext_messages', function() + local screen + + before_each(function() + clear{headless=false, args={"--cmd", "set shortmess-=I"}} + screen = Screen.new(80, 24) + screen:attach({rgb=true, ext_messages=true, ext_popupmenu=true}) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [3] = {bold = true}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [5] = {foreground = Screen.colors.Blue1}, + }) + end) + + it('supports intro screen', function() + -- intro message is not externalized. But check that it still works. + -- Note parts of it depends on version or is indeterministic. We ignore those parts. + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {IGNORE}| + {1:~ }| + {1:~ }Nvim is open source and freely distributable{1: }| + {1:~ }https://neovim.io/#chat{1: }| + {1:~ }| + {1:~ }type :help nvim{5:<Enter>} if you are new! {1: }| + {1:~ }type :checkhealth{5:<Enter>} to optimize Nvim{1: }| + {1:~ }type :q{5:<Enter>} to exit {1: }| + {1:~ }type :help{5:<Enter>} for help {1: }| + {1:~ }| + {IGNORE}| + {IGNORE}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + + feed("<c-l>") + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + + feed(":intro<cr>") + screen:expect{grid=[[ + | + | + | + | + | + | + {IGNORE}| + | + Nvim is open source and freely distributable | + https://neovim.io/#chat | + | + type :help nvim{5:<Enter>} if you are new! | + type :checkhealth{5:<Enter>} to optimize Nvim | + type :q{5:<Enter>} to exit | + type :help{5:<Enter>} for help | + | + {IGNORE}| + {IGNORE}| + | + | + | + | + | + | + ]], messages={ + {content = { { "Press ENTER or type command to continue", 4 } }, kind = "return_prompt" } + }} + end) +end) diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 8d35df6f48..7805ed3cb9 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -11,6 +11,7 @@ describe('ui/mouse/input', function() before_each(function() clear() meths.set_option('mouse', 'a') + meths.set_option('list', true) meths.set_option('listchars', 'eol:$') screen = Screen.new(25, 5) screen:attach() @@ -82,7 +83,7 @@ describe('ui/mouse/input', function() feed('<LeftMouse><0,0>') feed('<LeftRelease><0,0>') screen:expect([[ - ^t{1:esting}{3: } | + ^t{1:esting} | mouse | support and selection | {0:~ }| @@ -125,7 +126,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -162,7 +163,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -170,7 +171,7 @@ describe('ui/mouse/input', function() feed('<LeftMouse><11,0>') screen:expect{grid=[[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -178,7 +179,7 @@ describe('ui/mouse/input', function() feed('<LeftDrag><6,0>') screen:expect([[ {sel: + bar }{tab: + foo }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -192,7 +193,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -222,7 +223,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -260,7 +261,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -268,7 +269,7 @@ describe('ui/mouse/input', function() feed('<LeftMouse><11,0>') screen:expect{grid=[[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -276,7 +277,7 @@ describe('ui/mouse/input', function() feed('<LeftDrag><11,1>') screen:expect{grid=[[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -284,7 +285,7 @@ describe('ui/mouse/input', function() feed('<LeftDrag><6,1>') screen:expect([[ {sel: + bar }{tab: + foo }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -298,7 +299,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -347,7 +348,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -370,7 +371,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -393,7 +394,7 @@ describe('ui/mouse/input', function() insert('this is bar') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r | + this is ba^r{0:$} | {0:~ }| {0:~ }| | @@ -401,7 +402,7 @@ describe('ui/mouse/input', function() feed('<2-LeftMouse><4,0>') screen:expect([[ {sel: Name] }{tab: + foo + bar }{fill: }{tab:X}| - ^ | + {0:^$} | {0:~ }| {0:~ }| | @@ -440,16 +441,34 @@ describe('ui/mouse/input', function() local test_click = function(name, click_str, click_num, mouse_button, modifiers) - it(name .. ' works', function() + + local function doit(do_click) eq(1, funcs.has('tablineat')) - feed(click_str .. '<3,0>') + do_click(0,3) check_reply({0, click_num, mouse_button, modifiers}) - feed(click_str .. '<4,0>') + do_click(0,4) check_reply({}) - feed(click_str .. '<6,0>') + do_click(0,6) check_reply({5, click_num, mouse_button, modifiers, 2}) - feed(click_str .. '<13,0>') + do_click(0,13) check_reply({5, click_num, mouse_button, modifiers, 2}) + end + + it(name .. ' works (pseudokey)', function() + doit(function (row,col) + feed(click_str .. '<' .. col .. ',' .. row .. '>') + end) + end) + + it(name .. ' works (nvim_input_mouse)', function() + doit(function (row,col) + local buttons = {l='left',m='middle',r='right'} + local modstr = (click_num > 1) and tostring(click_num) or '' + for char in string.gmatch(modifiers, '%w') do + modstr = modstr .. char .. '-' -- - not needed but should be accepted + end + meths.input_mouse(buttons[mouse_button], 'press', modstr, 0, row, col) + end) end) end @@ -499,14 +518,14 @@ describe('ui/mouse/input', function() feed('<LeftDrag><2,2>') screen:expect([[ testing | - mo{1:use}{3: } | + mo{1:use} | {1:su}^pport and selection | {0:~ }| {2:-- VISUAL --} | ]]) feed('<LeftDrag><0,0>') screen:expect([[ - ^t{1:esting}{3: } | + ^t{1:esting} | {1:mou}se | support and selection | {0:~ }| @@ -537,7 +556,7 @@ describe('ui/mouse/input', function() feed('<LeftMouse><0,1>') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - ^this is bar | + ^this is bar{0:$} | {0:~ }| {0:~ }| :tabprevious | @@ -545,7 +564,7 @@ describe('ui/mouse/input', function() feed('<LeftDrag><4,1>') screen:expect([[ {tab: + foo }{sel: + bar }{fill: }{tab:X}| - {vis:this}^ is bar | + {vis:this}^ is bar{0:$} | {0:~ }| {0:~ }| {sel:-- VISUAL --} | @@ -568,7 +587,7 @@ describe('ui/mouse/input', function() screen:expect([[ testing | mouse | - {1:su}^p{1:port and selection}{3: } | + {1:su}^p{1:port and selection} | {0:~ }| {2:-- VISUAL LINE --} | ]]) @@ -596,8 +615,8 @@ describe('ui/mouse/input', function() ]]) feed('<RightMouse><2,2>') screen:expect([[ - {1:testing}{3: } | - {1:mouse}{3: } | + {1:testing} | + {1:mouse} | {1:su}^pport and selection | {0:~ }| {2:-- VISUAL --} | @@ -617,7 +636,7 @@ describe('ui/mouse/input', function() feed('<cr>') end) - it('mouse whell will target the hovered window', function() + local function wheel(use_api) feed('ggdG') insert([[ Inserting @@ -647,7 +666,11 @@ describe('ui/mouse/input', function() {4:[No Name] [+] }| :vsp | ]]) - feed('<ScrollWheelDown><0,0>') + if use_api then + meths.input_mouse('wheel', 'down', '', 0, 0, 0) + else + feed('<ScrollWheelDown><0,0>') + end screen:expect([[ mouse scrolling {4:│}lines | ^ {4:│}to | @@ -664,7 +687,11 @@ describe('ui/mouse/input', function() {4:[No Name] [+] }| :vsp | ]]) - feed('<ScrollWheelUp><27,0>') + if use_api then + meths.input_mouse('wheel', 'up', '', 0, 0, 27) + else + feed('<ScrollWheelUp><27,0>') + end screen:expect([[ mouse scrolling {4:│}text | ^ {4:│}with | @@ -681,7 +708,12 @@ describe('ui/mouse/input', function() {4:[No Name] [+] }| :vsp | ]]) - feed('<ScrollWheelUp><27,7><ScrollWheelUp>') + if use_api then + meths.input_mouse('wheel', 'up', '', 0, 7, 27) + meths.input_mouse('wheel', 'up', '', 0, 7, 27) + else + feed('<ScrollWheelUp><27,7><ScrollWheelUp>') + end screen:expect([[ mouse scrolling {4:│}text | ^ {4:│}with | @@ -698,9 +730,17 @@ describe('ui/mouse/input', function() {4:[No Name] [+] }| :vsp | ]]) + end + + it('mouse wheel will target the hovered window (pseudokey)', function() + wheel(false) end) - it('horizontal scrolling', function() + it('mouse wheel will target the hovered window (nvim_input_mouse)', function() + wheel(true) + end) + + it('horizontal scrolling (pseudokey)', function() command('set sidescroll=0') feed("<esc>:set nowrap<cr>") @@ -732,6 +772,39 @@ describe('ui/mouse/input', function() ]]) end) + it('horizontal scrolling (nvim_input_mouse)', function() + command('set sidescroll=0') + feed("<esc>:set nowrap<cr>") + + feed("a <esc>20Ab<esc>") + screen:expect([[ + | + | + bbbbbbbbbbbbbbb^b | + {0:~ }| + | + ]]) + + meths.input_mouse('wheel', 'left', '', 0, 0, 27) + screen:expect([[ + | + | + n bbbbbbbbbbbbbbbbbbb^b | + {0:~ }| + | + ]]) + + feed("^") + meths.input_mouse('wheel', 'right', '', 0, 0, 0) + screen:expect([[ + g | + | + ^t and selection bbbbbbbbb| + {0:~ }| + | + ]]) + end) + describe('on concealed text', function() -- Helpful for reading the test expectations: -- :match Error /\^/ diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index a5d4e34000..c54d608ec4 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -3,9 +3,11 @@ local Screen = require('test.functional.ui.screen') local clear = helpers.clear local feed, command, insert = helpers.feed, helpers.command, helpers.insert local eq = helpers.eq +local meths = helpers.meths +local wait = helpers.wait -describe('multigrid screen', function() +describe('ext_multigrid', function() local screen before_each(function() @@ -1521,4 +1523,337 @@ describe('multigrid screen', function() {1:~ }| ]]) end) + + it('supports mouse', function() + insert('some text\nto be clicked') + screen:expect([[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + | + ## grid 2 + some text | + to be clicke^d | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + + meths.input_mouse('left', 'press', '', 2, 0, 5) + screen:expect([[ + ## grid 1 + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + | + ## grid 2 + some ^text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + + feed(':new<cr>') + insert('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo') + + screen:expect([[ + ## grid 1 + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + {11:[No Name] [+] }| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {12:[No Name] [+] }| + | + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + Lorem ipsum dolor sit amet, consectetur adipiscing el| + it, sed do eiusm^o | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + + meths.input_mouse('left', 'press', '', 2, 1, 6) + screen:expect([[ + ## grid 1 + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + {12:[No Name] [+] }| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {11:[No Name] [+] }| + | + ## grid 2 + some text | + to be ^clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + Lorem ipsum dolor sit amet, consectetur adipiscing el| + it, sed do eiusmo | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + + meths.input_mouse('left', 'press', '', 3, 1, 4) + screen:expect([[ + ## grid 1 + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + {11:[No Name] [+] }| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {12:[No Name] [+] }| + | + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + Lorem ipsum dolor sit amet, consectetur adipiscing el| + it, ^sed do eiusmo | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + + screen:try_resize_grid(3, 80, 2) + screen:expect([[ + ## grid 1 + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + {11:[No Name] [+] }| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {12:[No Name] [+] }| + | + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, ^sed do eiusmo | + {1:~ }| + ]]) + + meths.input_mouse('left', 'press', '', 3, 0, 64) + screen:expect([[ + ## grid 1 + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + {11:[No Name] [+] }| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {12:[No Name] [+] }| + | + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do ^eiusmo | + {1:~ }| + ]]) + + meths.input_mouse('left', 'press', '', 1,6, 20) + -- TODO(bfredl): "batching" input_mouse is formally not supported yet. + -- Normally it should work fine in async context when nvim is not blocked, + -- but add a wait be sure. + wait() + meths.input_mouse('left', 'drag', '', 1, 4, 20) + screen:expect([[ + ## grid 1 + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + {11:[No Name] [+] }| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {12:[No Name] [+] }| + | + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do ^eiusmo | + {1:~ }| + ]]) + + feed('<c-w><c-w><c-w>v') + screen:expect([[ + ## grid 1 + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + {12:[No Name] [+] }| + [4:--------------------------]{12:│}[2:--------------------------]| + [4:--------------------------]{12:│}[2:--------------------------]| + [4:--------------------------]{12:│}[2:--------------------------]| + [4:--------------------------]{12:│}[2:--------------------------]| + [4:--------------------------]{12:│}[2:--------------------------]| + [4:--------------------------]{12:│}[2:--------------------------]| + [4:--------------------------]{12:│}[2:--------------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + | + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo | + {1:~ }| + ## grid 4 + some text | + to be ^clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + + meths.input_mouse('left', 'press', '', 1,8, 26) + wait() + meths.input_mouse('left', 'drag', '', 1, 6, 30) + screen:expect([[ + ## grid 1 + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + [3:-----------------------------------------------------]| + {12:[No Name] [+] }| + [4:------------------------------]{12:│}[2:----------------------]| + [4:------------------------------]{12:│}[2:----------------------]| + [4:------------------------------]{12:│}[2:----------------------]| + [4:------------------------------]{12:│}[2:----------------------]| + [4:------------------------------]{12:│}[2:----------------------]| + [4:------------------------------]{12:│}[2:----------------------]| + [4:------------------------------]{12:│}[2:----------------------]| + {11:[No Name] [+] }{12:[No Name] [+] }| + | + ## grid 2 + some text | + to be clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo | + {1:~ }| + ## grid 4 + some text | + to be ^clicked | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + end) end) diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index c26fa5e29b..ed630259be 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -18,6 +18,7 @@ describe('ui receives option updates', function() guifontset='', guifontwide='', linespace=0, + pumblend=0, showtabline=1, termguicolors=false, ext_cmdline=false, @@ -27,6 +28,8 @@ describe('ui receives option updates', function() ext_linegrid=false, ext_hlstate=false, ext_multigrid=false, + ext_messages=false, + ext_termcolors=false, } clear(...) diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 9424931de4..9a8c5a5789 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -5,6 +5,7 @@ local source = helpers.source local insert = helpers.insert local meths = helpers.meths local command = helpers.command +local funcs = helpers.funcs describe('ui/ext_popupmenu', function() local screen @@ -368,7 +369,7 @@ describe('ui/ext_popupmenu', function() end) -describe('popup placement', function() +describe('builtin popupmenu', function() local screen before_each(function() clear() @@ -385,7 +386,8 @@ describe('popup placement', function() [2] = {bold = true}, [3] = {reverse = true}, [4] = {bold = true, reverse = true}, - [5] = {bold = true, foreground = Screen.colors.SeaGreen} + [5] = {bold = true, foreground = Screen.colors.SeaGreen}, + [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, }) end) @@ -607,4 +609,880 @@ describe('popup placement', function() {2:-- }{5:match 1 of 3} | ]]) end) + + it('works with split and scroll', function() + screen:try_resize(60,14) + command("split") + command("set completeopt+=noinsert") + command("set mouse=a") + insert([[ + Lorem ipsum dolor sit amet, consectetur + adipisicing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud + exercitation ullamco laboris nisi ut aliquip ex + ea commodo consequat. Duis aute irure dolor in + reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa + qui officia deserunt mollit anim id est + laborum. + ]]) + + screen:expect([[ + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum. | + ^ | + {4:[No Name] [+] }| + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {3:[No Name] [+] }| + | + ]]) + + feed('ggOEst <c-x><c-p>') + screen:expect([[ + Est ^ | + L{n: sunt }{s: }sit amet, consectetur | + a{n: in }{s: }sed do eiusmod tempor | + i{n: culpa }{s: }re et dolore magna aliqua. | + U{n: qui }{s: }eniam, quis nostrud | + e{n: officia }{s: }co laboris nisi ut aliquip ex | + {4:[No}{n: deserunt }{s: }{4: }| + L{n: mollit }{s: }sit amet, consectetur | + a{n: anim }{s: }sed do eiusmod tempor | + i{n: id }{s: }re et dolore magna aliqua. | + U{n: est }{s: }eniam, quis nostrud | + e{n: laborum }{c: }co laboris nisi ut aliquip ex | + {3:[No}{s: Est }{c: }{3: }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 9, 40) + screen:expect([[ + Est ^ | + L{n: sunt }{s: }sit amet, consectetur | + a{n: in }{s: }sed do eiusmod tempor | + i{n: culpa }{s: }re et dolore magna aliqua. | + U{n: qui }{s: }eniam, quis nostrud | + e{n: officia }{s: }co laboris nisi ut aliquip ex | + {4:[No}{n: deserunt }{s: }{4: }| + U{n: mollit }{s: }eniam, quis nostrud | + e{n: anim }{s: }co laboris nisi ut aliquip ex | + e{n: id }{s: }at. Duis aute irure dolor in | + r{n: est }{s: }oluptate velit esse cillum | + d{n: laborum }{c: }ulla pariatur. Excepteur sint | + {3:[No}{s: Est }{c: }{3: }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + feed('e') + screen:expect([[ + Est e^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + U{n: ea }veniam, quis nostrud | + e{n: esse }mco laboris nisi ut aliquip ex | + e{n: eu }uat. Duis aute irure dolor in | + r{s: est }voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + meths.input_mouse('wheel', 'up', '', 0, 9, 40) + screen:expect([[ + Est e^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + L{n: ea } sit amet, consectetur | + a{n: esse } sed do eiusmod tempor | + i{n: eu }ore et dolore magna aliqua. | + U{s: est }veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + feed('s') + screen:expect([[ + Est es^ | + L{n: esse } sit amet, consectetur | + a{s: est } sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {4:[No Name] [+] }| + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 9, 40) + screen:expect([[ + Est es^ | + L{n: esse } sit amet, consectetur | + a{s: est } sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {4:[No Name] [+] }| + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + feed('<bs>') + screen:expect([[ + Est e^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + U{n: ea }veniam, quis nostrud | + e{n: esse }mco laboris nisi ut aliquip ex | + e{n: eu }uat. Duis aute irure dolor in | + r{s: est }voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65} | + ]]) + + feed('<c-p>') + screen:expect([[ + Est eu^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + U{n: ea }veniam, quis nostrud | + e{n: esse }mco laboris nisi ut aliquip ex | + e{s: eu }uat. Duis aute irure dolor in | + r{n: est }voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 9, 40) + screen:expect([[ + Est eu^ | + L{n: elit } sit amet, consectetur | + a{n: eiusmod } sed do eiusmod tempor | + i{n: et }ore et dolore magna aliqua. | + U{n: enim }veniam, quis nostrud | + e{n: exercitation }mco laboris nisi ut aliquip ex | + {4:[No}{n: ex }{4: }| + r{n: ea }voluptate velit esse cillum | + d{n: esse }nulla pariatur. Excepteur sint | + o{s: eu }t non proident, sunt in culpa | + q{n: est }unt mollit anim id est | + laborum. | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65} | + ]]) + + + funcs.complete(4, {'ea', 'eeeeeeeeeeeeeeeeee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'}) + screen:expect([[ + Est eu^ | + {s: ea }t amet, consectetur | + {n: eeeeeeeeeeeeeeeeee }d do eiusmod tempor | + {n: ei } et dolore magna aliqua. | + {n: eo }iam, quis nostrud | + {n: eu } laboris nisi ut aliquip ex | + {4:[N}{n: ey }{4: }| + {n: eå }uptate velit esse cillum | + {n: eä }la pariatur. Excepteur sint | + {n: eö }on proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum. | + {3:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 9} | + ]]) + + funcs.complete(4, {'ea', 'eee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'}) + screen:expect([[ + Est eu^ | + {s: ea }r sit amet, consectetur | + {n: eee }, sed do eiusmod tempor | + {n: ei }bore et dolore magna aliqua. | + {n: eo } veniam, quis nostrud | + {n: eu }amco laboris nisi ut aliquip ex | + {4:[N}{n: ey }{4: }| + {n: eå } voluptate velit esse cillum | + {n: eä } nulla pariatur. Excepteur sint | + {n: eö }at non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum. | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + + feed('<c-n>') + screen:expect([[ + Esteee^ | + {n: ea }r sit amet, consectetur | + {s: eee }, sed do eiusmod tempor | + {n: ei }bore et dolore magna aliqua. | + {n: eo } veniam, quis nostrud | + {n: eu }amco laboris nisi ut aliquip ex | + {4:[N}{n: ey }{4: }| + {n: eå } voluptate velit esse cillum | + {n: eä } nulla pariatur. Excepteur sint | + {n: eö }at non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum. | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + + funcs.complete(6, {'foo', 'bar'}) + screen:expect([[ + Esteee^ | + Lo{s: foo }sit amet, consectetur | + ad{n: bar }sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {4:[No Name] [+] }| + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum. | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + + feed('<c-y>') + screen:expect([[ + Esteefoo^ | + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {4:[No Name] [+] }| + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum. | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + end) + + it('can be moved due to wrap or resize', function() + feed('isome long prefix before the ') + command("set completeopt+=noinsert,noselect") + command("set linebreak") + funcs.complete(29, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + some long prefix before the ^ | + {1:~ }{n: word }| + {1:~ }{n: choice}| + {1:~ }{n: text }| + {1:~ }{n: thing }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-p>') + screen:expect([[ + some long prefix before the | + thing^ | + {n:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {s:thing }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-p>') + screen:expect([[ + some long prefix before the text| + {1:^~ }{n: word }| + {1:~ }{n: choice}| + {1:~ }{s: text }| + {1:~ }{n: thing }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(30,8) + screen:expect([[ + some long prefix before the | + text^ | + {n:word }{1: }| + {n:choice }{1: }| + {s:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(50,8) + screen:expect([[ + some long prefix before the text^ | + {1:~ }{n: word }{1: }| + {1:~ }{n: choice }{1: }| + {1:~ }{s: text }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(25,10) + screen:expect([[ + some long prefix before | + the text^ | + {1:~ }{n: word }{1: }| + {1:~ }{n: choice }{1: }| + {1:~ }{s: text }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + screen:try_resize(12,5) + screen:expect([[ + some long | + prefix | + bef{n: word } | + tex{n: }^ | + {2:-- }{s: text } | + ]]) + + -- can't draw the pum, but check we don't crash + screen:try_resize(12,2) + screen:expect([[ + text^ | + {2:-- INSERT -} | + ]]) + + -- but state is preserved, pum reappears + screen:try_resize(20,8) + screen:expect([[ + some long prefix | + before the text^ | + {1:~ }{n: word }| + {1:~ }{n: choice }| + {1:~ }{s: text }| + {1:~ }{n: thing }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end) + + it('works with rightleft window', function() + command("set rl") + feed('isome rightleft ') + screen:expect([[ + ^ tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {2:-- INSERT --} | + ]]) + + command("set completeopt+=noinsert,noselect") + funcs.complete(16, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + ^ tfelthgir emos| + {1: }{n: drow}{1: ~}| + {1: }{n: eciohc}{1: ~}| + {1: }{n: txet}{1: ~}| + {1: }{n: gniht}{1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {2:-- INSERT --} | + ]]) + + feed('<c-n>') + screen:expect([[ + ^ drow tfelthgir emos| + {1: }{s: drow}{1: ~}| + {1: }{n: eciohc}{1: ~}| + {1: }{n: txet}{1: ~}| + {1: }{n: gniht}{1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {2:-- INSERT --} | + ]]) + + feed('<c-y>') + screen:expect([[ + ^ drow tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {2:-- INSERT --} | + ]]) + end) + + it('works with multiline messages', function() + screen:try_resize(40,8) + feed('ixx<cr>') + command('imap <f2> <cmd>echoerr "very"\\|echoerr "much"\\|echoerr "error"<cr>') + funcs.complete(1, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + xx | + word^ | + {s:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<f2>') + screen:expect([[ + xx | + word | + {s:word }{1: }| + {4: }| + {6:very} | + {6:much} | + {6:error} | + {5:Press ENTER or type command to continue}^ | + ]]) + + feed('<cr>') + screen:expect([[ + xx | + word^ | + {s:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-n>') + screen:expect([[ + xx | + choice^ | + {n:word }{1: }| + {s:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + command("split") + screen:expect([[ + xx | + choice^ | + {n:word }{1: }| + {s:choice }{4: }| + {n:text } | + {n:thing } | + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 6, 15) + screen:expect([[ + xx | + choice^ | + {n:word }{1: }| + {s:choice }{4: }| + {n:text } | + {n:thing }{1: }| + {3:[No Name] [+] }| + {2:-- INSERT --} | + ]]) + end) + + it('works with kind, menu and abbr attributes', function() + screen:try_resize(40,8) + feed('ixx ') + funcs.complete(4, {{word='wordey', kind= 'x', menu='extrainfo'}, 'thing', {word='secret', abbr='sneaky', menu='bar'}}) + screen:expect([[ + xx wordey^ | + {1:~ }{s: wordey x extrainfo }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }{n: sneaky bar }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-p>') + screen:expect([[ + xx ^ | + {1:~ }{n: wordey x extrainfo }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }{n: sneaky bar }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<c-p>') + screen:expect([[ + xx secret^ | + {1:~ }{n: wordey x extrainfo }{1: }| + {1:~ }{n: thing }{1: }| + {1:~ }{s: sneaky bar }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<esc>') + screen:expect([[ + xx secre^t | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) + + it("'pumblend' RGB-color", function() + screen:try_resize(60,14) + screen:set_default_attr_ids({ + [1] = {background = Screen.colors.Yellow}, + [2] = {bold = true, reverse = true}, + [3] = {bold = true, foreground = Screen.colors.Brown}, + [4] = {foreground = Screen.colors.Blue1}, + [5] = {reverse = true}, + [6] = {background = Screen.colors.Gray55, foreground = Screen.colors.Grey45}, + [7] = {background = Screen.colors.Gray55, foreground = Screen.colors.Grey0}, + [8] = {background = tonumber('0x191919'), foreground = Screen.colors.Grey0}, + [9] = {background = tonumber('0xffc1ff'), foreground = tonumber('0xe5a8e5')}, + [10] = {background = tonumber('0xffc1ff'), foreground = Screen.colors.Grey0}, + [11] = {foreground = tonumber('0xffc1ff'), background = tonumber('0xe5a8e5'), bold = true}, + [12] = {foreground = Screen.colors.Grey55, background = Screen.colors.Gray45, bold = true}, + [13] = {background = tonumber('0xffc1e5'), foreground = Screen.colors.Grey0}, + [14] = {background = tonumber('0xffc1e5'), foreground = tonumber('0xe5a8e5')}, + [15] = {background = tonumber('0xffc1ff'), foreground = tonumber('0x080202')}, + [16] = {background = tonumber('0xffc1ff'), bold = true, foreground = tonumber('0xf6ace9')}, + [17] = {background = tonumber('0xffc1ff'), foreground = tonumber('0xe5a8ff')}, + [18] = {background = tonumber('0xe5a8e5'), foreground = tonumber('0xffc1ff')}, + [19] = {background = Screen.colors.Gray45, foreground = Screen.colors.Grey55}, + [20] = {bold = true}, + [21] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [22] = {background = Screen.colors.WebGray}, + [23] = {background = Screen.colors.Grey0}, + [24] = {background = Screen.colors.LightMagenta}, + [25] = {background = Screen.colors.Gray75, foreground = Screen.colors.Grey25}, + [26] = {background = Screen.colors.Gray75, foreground = Screen.colors.Grey0}, + [27] = {background = Screen.colors.Gray50, foreground = Screen.colors.Grey0}, + [28] = {background = tonumber('0xffddff'), foreground = tonumber('0x7f5d7f')}, + [29] = {background = tonumber('0xffddff'), foreground = Screen.colors.Grey0}, + [30] = {foreground = tonumber('0xffddff'), background = tonumber('0x7f5d7f'), bold = true}, + [31] = {foreground = tonumber('0xffddff'), background = Screen.colors.Grey0, bold = true}, + [32] = {foreground = Screen.colors.Gray75, background = Screen.colors.Grey25, bold = true}, + [33] = {background = tonumber('0xffdd7f'), foreground = Screen.colors.Grey0}, + [34] = {background = tonumber('0xffdd7f'), foreground = tonumber('0x7f5d7f')}, + [35] = {background = tonumber('0xffddff'), bold = true, foreground = tonumber('0x290a0a')}, + [36] = {background = tonumber('0xffddff'), bold = true, foreground = tonumber('0xd27294')}, + [37] = {background = tonumber('0xffddff'), foreground = tonumber('0x7f5dff')}, + [38] = {background = tonumber('0x7f5d7f'), foreground = tonumber('0xffddff')}, + [39] = {background = Screen.colors.Grey0, foreground = tonumber('0xffddff')}, + [40] = {background = Screen.colors.Gray25, foreground = Screen.colors.Grey75}, + [41] = {background = tonumber('0xffddff'), foreground = tonumber('0x00003f')}, + [42] = {foreground = tonumber('0x0c0c0c'), background = tonumber('0xe5a8e5')}, + [43] = {background = tonumber('0x7f5d7f'), bold = true, foreground = tonumber('0x3f3f3f')}, + [44] = {foreground = tonumber('0x3f3f3f'), background = tonumber('0x7f5d7f')}, + }) + command('syntax on') + command('set mouse=a') + command('set pumblend=10') + insert([[ + Lorem ipsum dolor sit amet, consectetur + adipisicing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud + exercitation ullamco laboris nisi ut aliquip ex + ea commodo consequat. Duis aute irure dolor in + reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa + qui officia deserunt mollit anim id est + laborum.]]) + command('match Statement /el/') + command('2match Comment /ut/') + command('1') + command('split') + command('/ol') + screen:expect([[ + Lorem ipsum d{1:ol}or sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + ^incididunt ut labore et d{1:ol}ore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + ea commodo consequat. Duis aute irure d{1:ol}or in | + {2:[No Name] [+] }| + Lorem ipsum d{1:ol}or sit amet, consectetur | + adipisicing {3:el}it, sed do eiusmod tempor | + incididunt {4:ut} labore et d{1:ol}ore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi {4:ut} aliquip ex | + {5:[No Name] [+] }| + | + ]]) + + feed('Obla bla <c-x><c-n>') + screen:expect([[ + Lorem ipsum d{1:ol}or sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + bla bla incididunt^ | + incidid{6:u}{7:incididunt}{6:re et}{8: }d{1:ol}ore magna aliqua. | + Ut enim{9: }{10:ut}{9: minim veniam}{6:,} quis nostrud | + exercit{9:a}{10:labore}{9:llamco la}{6:b}oris nisi ut aliquip ex | + {2:[No Nam}{11:e}{42:et}{11:[+] }{12: }{2: }| + Lorem i{9:p}{10:dolor}{13:e}{14:l}{9:or sit a}{6:m}et, consectetur | + adipisi{9:c}{10:magn}{15:a}{16:l}{9:it, sed d}{6:o} eiusmod tempor | + bla bla{9: }{10:aliqua}{9:dunt }{6: } | + incidid{9:u}{10:Ut}{9: }{17:ut}{9: labore et}{6: }d{1:ol}ore magna aliqua. | + Ut enim{9: }{10:enim}{9:inim veniam}{6:,} quis nostrud | + {5:[No Nam}{18:e}{42:ad}{18:[+] }{19: }{5: }| + {20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} | + ]]) + + command('set pumblend=0') + screen:expect([[ + Lorem ipsum d{1:ol}or sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + bla bla incididunt^ | + incidid{22: incididunt }{23: }d{1:ol}ore magna aliqua. | + Ut enim{24: ut }{22: } quis nostrud | + exercit{24: labore }{22: }oris nisi ut aliquip ex | + {2:[No Nam}{24: et }{22: }{2: }| + Lorem i{24: dolore }{22: }et, consectetur | + adipisi{24: magna }{22: } eiusmod tempor | + bla bla{24: aliqua }{22: } | + incidid{24: Ut }{22: }d{1:ol}ore magna aliqua. | + Ut enim{24: enim }{22: } quis nostrud | + {5:[No Nam}{24: ad }{22: }{5: }| + {20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} | + ]]) + + command('set pumblend=50') + screen:expect([[ + Lorem ipsum d{1:ol}or sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + bla bla incididunt^ | + incidid{25:u}{26:incididunt}{25:re et}{27: }d{1:ol}ore magna aliqua. | + Ut enim{28: }{29:ut}{28: minim veniam}{25:,} quis nostrud | + exercit{28:a}{29:labore}{28:llamco la}{25:b}oris nisi ut aliquip ex | + {2:[No Nam}{30:e}{43:et}{30:[+] }{32: }{2: }| + Lorem i{28:p}{29:dolor}{33:e}{34:l}{28:or sit a}{25:m}et, consectetur | + adipisi{28:c}{29:magn}{35:a}{36:l}{28:it, sed d}{25:o} eiusmod tempor | + bla bla{28: }{29:aliqua}{28:dunt }{25: } | + incidid{28:u}{29:Ut}{28: }{37:ut}{28: labore et}{25: }d{1:ol}ore magna aliqua. | + Ut enim{28: }{29:enim}{28:inim veniam}{25:,} quis nostrud | + {5:[No Nam}{38:e}{44:ad}{38:[+] }{40: }{5: }| + {20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} | + ]]) + + meths.input_mouse('wheel', 'down', '', 0, 9, 40) + screen:expect([[ + Lorem ipsum d{1:ol}or sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + bla bla incididunt^ | + incidid{25:u}{26:incididunt}{25:re et}{27: }d{1:ol}ore magna aliqua. | + Ut enim{28: }{29:ut}{28: minim veniam}{25:,} quis nostrud | + exercit{28:a}{29:labore}{28:llamco la}{25:b}oris nisi ut aliquip ex | + {2:[No Nam}{30:e}{43:et}{30:[+] }{32: }{2: }| + incidid{28:u}{29:dol}{41:or}{29:e}{28:labore et}{25: }d{1:ol}ore magna aliqua. | + Ut enim{28: }{29:magna}{28:nim veniam}{25:,} quis nostrud | + exercit{28:a}{29:aliqua}{28:llamco la}{25:b}oris nisi {4:ut} aliquip ex | + ea comm{28:o}{29:Ut}{28: consequat. D}{25:u}is a{4:ut}e irure d{1:ol}or in | + reprehe{28:n}{29:enim}{28:t in v}{34:ol}{28:upt}{25:a}te v{3:el}it esse cillum | + {5:[No Nam}{38:e}{44:ad}{38:[+] }{40: }{5: }| + {20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} | + ]]) + + feed('<c-e>') + screen:expect([[ + Lorem ipsum d{1:ol}or sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + bla bla ^ | + incididunt ut labore et d{1:ol}ore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + {2:[No Name] [+] }| + incididunt {4:ut} labore et d{1:ol}ore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi {4:ut} aliquip ex | + ea commodo consequat. Duis a{4:ut}e irure d{1:ol}or in | + reprehenderit in v{1:ol}uptate v{3:el}it esse cillum | + {5:[No Name] [+] }| + {20:-- INSERT --} | + ]]) + end) + + it("'pumblend' 256-color (non-RGB)", function() + screen:detach() + screen = Screen.new(60, 8) + screen:attach({rgb=false, ext_popupmenu=false}) + screen:set_default_attr_ids({ + [1] = {foreground = Screen.colors.Grey0, background = tonumber('0x000007')}, + [2] = {foreground = tonumber('0x000055'), background = tonumber('0x000007')}, + [3] = {foreground = tonumber('0x00008f'), background = Screen.colors.Grey0}, + [4] = {foreground = Screen.colors.Grey0, background = tonumber('0x0000e1')}, + [5] = {foreground = tonumber('0x0000d1'), background = tonumber('0x0000e1')}, + [6] = {foreground = Screen.colors.NavyBlue, background = tonumber('0x0000f8')}, + [7] = {foreground = tonumber('0x0000a5'), background = tonumber('0x0000f8')}, + [8] = {foreground = tonumber('0x00000c')}, + [9] = {bold = true}, + [10] = {foreground = tonumber('0x000002')}, + }) + command('set notermguicolors pumblend=10') + insert([[ + Lorem ipsum dolor sit amet, consectetur + adipisicing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud + laborum.]]) + + feed('ggOdo<c-x><c-n>') + screen:expect([[ + dolor^ | + {1:dolor}{2: ipsum dol}or sit amet, consectetur | + {4:do}{5:ipisicing eli}t, sed do eiusmod tempor | + {4:dolore}{5:dunt ut l}abore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + laborum. | + {8:~ }| + {9:-- Keyword Local completion (^N^P) }{10:match 1 of 3} | + ]]) + end) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 69f4a44dd8..2eae549ebd 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -159,6 +159,11 @@ function Screen.new(width, height) wildmenu_selected = nil, win_position = {}, _session = nil, + messages = {}, + msg_history = {}, + showmode = {}, + showcmd = {}, + ruler = {}, _default_attr_ids = nil, _default_attr_ignore = nil, _mouse_enabled = true, @@ -250,7 +255,8 @@ end -- canonical order of ext keys, used to generate asserts local ext_keys = { - 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos' + 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos', + 'messages', 'showmode', 'showcmd', 'ruler', } -- Asserts that the screen state eventually matches an expected state @@ -392,7 +398,7 @@ function Screen:expect(expected, attr_ids, attr_ignore) .. ') differs from configured height(' .. #actual_rows .. ') of Screen.' end for i = 1, #actual_rows do - if expected_rows[i] ~= actual_rows[i] then + if expected_rows[i] ~= actual_rows[i] and expected_rows[i] ~= "{IGNORE}|" then local msg_expected_rows = {} for j = 1, #expected_rows do msg_expected_rows[j] = expected_rows[j] @@ -917,7 +923,7 @@ function Screen:_handle_option_set(name, value) end function Screen:_handle_popupmenu_show(items, selected, row, col) - self.popupmenu = {items=items,pos=selected, anchor={row, col}} + self.popupmenu = {items=items, pos=selected, anchor={row, col}} end function Screen:_handle_popupmenu_select(selected) @@ -973,6 +979,34 @@ function Screen:_handle_wildmenu_hide() self.wildmenu_items, self.wildmenu_pos = nil, nil end +function Screen:_handle_msg_show(kind, chunks, replace_last) + local pos = #self.messages + if not replace_last or pos == 0 then + pos = pos + 1 + end + self.messages[pos] = {kind=kind, content=chunks} +end + +function Screen:_handle_msg_clear() + self.messages = {} +end + +function Screen:_handle_msg_showcmd(msg) + self.showcmd = msg +end + +function Screen:_handle_msg_showmode(msg) + self.showmode = msg +end + +function Screen:_handle_msg_ruler(msg) + self.ruler = msg +end + +function Screen:_handle_msg_history_show(entries) + self.msg_history = entries +end + function Screen:_clear_block(grid, top, bot, left, right) for i = top, bot do self:_clear_row_section(grid, i, left, right) @@ -1057,12 +1091,27 @@ function Screen:_extstate_repr(attr_state) cmdline_block[i] = self:_chunks_repr(entry, attr_state) end + local messages = {} + for i, entry in ipairs(self.messages) do + messages[i] = {kind=entry.kind, content=self:_chunks_repr(entry.content, attr_state)} + end + + local msg_history = {} + for i, entry in ipairs(self.msg_history) do + messages[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)} + end + return { popupmenu=self.popupmenu, cmdline=cmdline, cmdline_block=cmdline_block, wildmenu_items=self.wildmenu_items, wildmenu_pos=self.wildmenu_pos, + messages=messages, + showmode=self:_chunks_repr(self.showmode, attr_state), + showcmd=self:_chunks_repr(self.showcmd, attr_state), + ruler=self:_chunks_repr(self.ruler, attr_state), + msg_history=msg_history, } end @@ -1303,6 +1352,8 @@ function Screen:_pprint_attrs(attrs) if f == "foreground" or f == "background" or f == "special" then if Screen.colornames[v] ~= nil then desc = "Screen.colors."..Screen.colornames[v] + else + desc = string.format("tonumber('0x%06x')",v) end end table.insert(items, f.." = "..desc) diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 04d532f6e1..46f0b5060c 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -960,3 +960,46 @@ end) describe("Screen (line-based)", function() screen_tests(true) end) + +describe('Screen default colors', function() + local screen + local function startup(light, termcolors) + local extra = (light and ' background=light') or '' + + local nvim_argv = {helpers.nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', + '--cmd', 'set shortmess+=I noswapfile belloff= noshowcmd noruler'..extra, + '--embed'} + local screen_nvim = spawn(nvim_argv) + set_session(screen_nvim) + screen = Screen.new() + screen:attach(termcolors and {rgb=true,ext_termcolors=true} or {rgb=true}) + end + + it('are dark per default', function() + startup(false, false) + screen:expect{condition=function() + eq({rgb_bg=0, rgb_fg=Screen.colors.White, rgb_sp=Screen.colors.Red, + cterm_bg=0, cterm_fg=0}, screen.default_colors) + end} + end) + + it('can be set to light', function() + startup(true, false) + screen:expect{condition=function() + eq({rgb_bg=Screen.colors.White, rgb_fg=0, rgb_sp=Screen.colors.Red, + cterm_bg=0, cterm_fg=0}, screen.default_colors) + end} + end) + + it('can be handled by external terminal', function() + startup(false, true) + screen:expect{condition=function() + eq({rgb_bg=-1, rgb_fg=-1, rgb_sp=-1, cterm_bg=0, cterm_fg=0}, screen.default_colors) + end} + + startup(true, true) + screen:expect{condition=function() + eq({rgb_bg=-1, rgb_fg=-1, rgb_sp=-1, cterm_bg=0, cterm_fg=0}, screen.default_colors) + end} + end) +end) diff --git a/test/helpers.lua b/test/helpers.lua index a6ed312213..59da274e87 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -1,3 +1,4 @@ +require('vim.compat') local assert = require('luassert') local luv = require('luv') local lfs = require('lfs') diff --git a/test/unit/api/helpers.lua b/test/unit/api/helpers.lua index 4fb1cee4b3..3d306d2b1b 100644 --- a/test/unit/api/helpers.lua +++ b/test/unit/api/helpers.lua @@ -114,8 +114,7 @@ local lua2obj_type_tab = { api.xmalloc(len * ffi.sizeof('KeyValuePair'))), }}) for i = 1, len do - local table_unpack = table.unpack or unpack -- luacheck: compat - local key, val = table_unpack(kvs[i]) + local key, val = unpack(kvs[i]) dct.data.dictionary.items[i - 1] = ffi.new( 'KeyValuePair', {key=ffi.gc(lua2obj(key), nil).data.string, value=ffi.gc(lua2obj(val), nil)}) |