diff options
Diffstat (limited to 'test/functional/terminal/tui_spec.lua')
-rw-r--r-- | test/functional/terminal/tui_spec.lua | 256 |
1 files changed, 187 insertions, 69 deletions
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 94690524d3..d4628ea626 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -4,33 +4,38 @@ -- "bracketed paste" terminal feature: -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode -local helpers = require('test.functional.helpers')(after_each) -local thelpers = require('test.functional.terminal.helpers') +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local eq = helpers.eq -local feed_data = thelpers.feed_data -local clear = helpers.clear -local command = helpers.command -local dedent = helpers.dedent -local exec = helpers.exec -local exec_lua = helpers.exec_lua -local testprg = helpers.testprg -local retry = helpers.retry -local nvim_prog = helpers.nvim_prog -local nvim_set = helpers.nvim_set -local ok = helpers.ok -local read_file = helpers.read_file -local fn = helpers.fn -local api = helpers.api -local is_ci = helpers.is_ci -local is_os = helpers.is_os -local new_pipename = helpers.new_pipename -local spawn_argv = helpers.spawn_argv -local set_session = helpers.set_session -local write_file = helpers.write_file -local eval = helpers.eval - -if helpers.skip(is_os('win')) then +local tt = require('test.functional.terminal.testutil') + +local eq = t.eq +local feed_data = tt.feed_data +local clear = n.clear +local command = n.command +local dedent = t.dedent +local exec = n.exec +local exec_lua = n.exec_lua +local testprg = n.testprg +local retry = t.retry +local nvim_prog = n.nvim_prog +local nvim_set = n.nvim_set +local ok = t.ok +local read_file = t.read_file +local fn = n.fn +local api = n.api +local is_ci = t.is_ci +local is_os = t.is_os +local new_pipename = n.new_pipename +local spawn_argv = n.spawn_argv +local set_session = n.set_session +local write_file = t.write_file +local eval = n.eval +local assert_log = t.assert_log + +local testlog = 'Xtest-tui-log' + +if t.skip(is_os('win')) then return end @@ -42,7 +47,7 @@ describe('TUI', function() before_each(function() clear() local child_server = new_pipename() - screen = thelpers.setup_child_nvim({ + screen = tt.setup_child_nvim({ '--listen', child_server, '-u', @@ -61,8 +66,8 @@ describe('TUI', function() | {3:-- TERMINAL --} | ]]) - child_session = helpers.connect(child_server) - child_exec_lua = thelpers.make_lua_executor(child_session) + child_session = n.connect(child_server) + child_exec_lua = tt.make_lua_executor(child_session) end) -- Wait for mode in the child Nvim (avoid "typeahead race" #10826). @@ -83,7 +88,6 @@ describe('TUI', function() end it('rapid resize #7572 #7628', function() - helpers.skip(helpers.is_asan(), 'Test extra unstable with ASAN. See #23762') -- Need buffer rows to provoke the behavior. feed_data(':edit test/functional/fixtures/bigfile.txt\n') screen:expect([[ @@ -1345,15 +1349,15 @@ describe('TUI', function() it('paste: big burst of input', function() feed_data(':set ruler\n') - local t = {} + local q = {} for i = 1, 3000 do - t[i] = 'item ' .. tostring(i) + q[i] = 'item ' .. tostring(i) end feed_data('i') wait_for_mode('i') -- "bracketed paste" - feed_data('\027[200~' .. table.concat(t, '\n') .. '\027[201~') - expect_child_buf_lines(t) + feed_data('\027[200~' .. table.concat(q, '\n') .. '\027[201~') + expect_child_buf_lines(q) feed_data(' end') screen:expect([[ item 2997 | @@ -1486,7 +1490,8 @@ describe('TUI', function() feed_data('\027[201~') -- phase 3 screen:expect_unchanged() local _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {}) - eq({ 1, 2, 3 }, rv) + -- In rare cases there may be multiple chunks of phase 2 because of timing. + eq({ 1, 2, 3 }, { rv[1], rv[2], rv[#rv] }) end) it('allows termguicolors to be set at runtime', function() @@ -1588,6 +1593,35 @@ describe('TUI', function() } end) + -- Note: libvterm doesn't support colored underline or undercurl. + it('supports undercurl and underdouble when run in :terminal', function() + screen:set_default_attr_ids({ + [1] = { reverse = true }, + [2] = { bold = true, reverse = true }, + [3] = { bold = true }, + [4] = { foreground = 12 }, + [5] = { undercurl = true }, + [6] = { underdouble = true }, + }) + child_session:request('nvim_set_hl', 0, 'Visual', { undercurl = true }) + feed_data('ifoobar\027V') + screen:expect([[ + {5:fooba}{1:r} | + {4:~ }|*3 + {2:[No Name] [+] }| + {3:-- VISUAL LINE --} | + {3:-- TERMINAL --} | + ]]) + child_session:request('nvim_set_hl', 0, 'Visual', { underdouble = true }) + screen:expect([[ + {6:fooba}{1:r} | + {4:~ }|*3 + {2:[No Name] [+] }| + {3:-- VISUAL LINE --} | + {3:-- TERMINAL --} | + ]]) + end) + it('in nvim_list_uis()', function() -- $TERM in :terminal. local exp_term = is_os('bsd') and 'builtin_xterm' or 'xterm-256color' @@ -1618,7 +1652,7 @@ describe('TUI', function() eq(expected, rv) end) - it('allows grid to assume wider ambiguous-width characters than host terminal #19686', function() + it('allows grid to assume wider ambiwidth chars than host terminal', function() child_session:request( 'nvim_buf_set_lines', 0, @@ -1662,8 +1696,52 @@ describe('TUI', function() screen:expect(singlewidth_screen) end) + it('allows grid to assume wider non-ambiwidth chars than host terminal', function() + child_session:request( + 'nvim_buf_set_lines', + 0, + 0, + -1, + true, + { ('✓'):rep(60), ('✓'):rep(60) } + ) + child_session:request('nvim_set_option_value', 'cursorline', true, {}) + child_session:request('nvim_set_option_value', 'list', true, {}) + child_session:request('nvim_set_option_value', 'listchars', 'eol:$', { win = 0 }) + feed_data('gg') + local singlewidth_screen = [[ + {13:✓}{12:✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓}| + {12:✓✓✓✓✓✓✓✓✓✓}{15:$}{12: }| + ✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓| + ✓✓✓✓✓✓✓✓✓✓{4:$} | + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]] + -- When grid assumes "✓" to be double-width but host terminal assumes it to be single-width, + -- the second cell of "✓" is a space and the attributes of the "✓" are applied to it. + local doublewidth_screen = [[ + {13:✓}{12: ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ }| + {12:✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ }| + {12:✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ }{15:$}{12: }| + ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ {4:@@@@}| + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]] + screen:expect(singlewidth_screen) + child_session:request('nvim_set_option_value', 'ambiwidth', 'double', {}) + screen:expect_unchanged() + child_session:request('nvim_call_function', 'setcellwidths', { { { 0x2713, 0x2713, 2 } } }) + screen:expect(doublewidth_screen) + child_session:request('nvim_set_option_value', 'ambiwidth', 'single', {}) + screen:expect_unchanged() + child_session:request('nvim_call_function', 'setcellwidths', { { { 0x2713, 0x2713, 1 } } }) + screen:expect(singlewidth_screen) + end) + it('draws correctly when cursor_address overflows #21643', function() - helpers.skip(is_os('mac'), 'FIXME: crashes/errors on macOS') + t.skip(is_os('mac'), 'FIXME: crashes/errors on macOS') screen:try_resize(77, 855) retry(nil, nil, function() eq({ true, 852 }, { child_session:request('nvim_win_get_height', 0) }) @@ -1925,6 +2003,39 @@ describe('TUI', function() ]]) end) + it('invalidated regions are cleared with terminal background attr', function() + local screen = Screen.new(50, 10) + screen:set_default_attr_ids({ [1] = { foreground = Screen.colors.Black } }) + screen:attach() + fn.termopen({ + nvim_prog, + '--clean', + '--cmd', + 'set termguicolors', + '--cmd', + 'sleep 10', + }, { + env = { + VIMRUNTIME = os.getenv('VIMRUNTIME'), + }, + }) + screen:expect({ + grid = [[ + {1:^ }| + {1: }|*8 + | + ]], + }) + screen:try_resize(51, 11) + screen:expect({ + grid = [[ + {1:^ }| + {1: }|*9 + | + ]], + }) + end) + it('argv[0] can be overridden #23953', function() if not exec_lua('return pcall(require, "ffi")') then pending('missing LuaJIT FFI') @@ -1941,7 +2052,7 @@ describe('TUI', function() finally(function() os.remove(script_file) end) - local screen = thelpers.setup_child_nvim({ '--clean', '-l', script_file }) + local screen = tt.setup_child_nvim({ '--clean', '-l', script_file }) screen:expect { grid = [[ {1: } | @@ -1969,7 +2080,7 @@ describe('TUI', function() finally(function() os.remove('testF') end) - local screen = thelpers.screen_setup( + local screen = tt.screen_setup( 0, ('"%s" -u NONE -i NONE --cmd "set noswapfile noshowcmd noruler" --cmd "normal iabc" > /dev/null 2>&1 && cat testF && rm testF'):format( nvim_prog @@ -1990,7 +2101,7 @@ describe('TUI', function() end) it('<C-h> #10134', function() - local screen = thelpers.setup_child_nvim({ + local screen = tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2023,7 +2134,7 @@ describe('TUI', function() end) it('draws line with many trailing spaces correctly #24955', function() - local screen = thelpers.setup_child_nvim({ + local screen = tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2062,7 +2173,7 @@ describe('TUI', function() it('no heap-buffer-overflow when changing &columns', function() -- Set a different bg colour and change $TERM to something dumber so the `print_spaces()` -- codepath in `clear_region()` is hit. - local screen = thelpers.setup_child_nvim({ + local screen = tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2105,7 +2216,7 @@ end) describe('TUI UIEnter/UILeave', function() it('fires exactly once, after VimEnter', function() clear() - local screen = thelpers.setup_child_nvim({ + local screen = tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2152,7 +2263,7 @@ describe('TUI FocusGained/FocusLost', function() before_each(function() clear() local child_server = new_pipename() - screen = thelpers.setup_child_nvim({ + screen = tt.setup_child_nvim({ '--listen', child_server, '-u', @@ -2172,7 +2283,7 @@ describe('TUI FocusGained/FocusLost', function() | {3:-- TERMINAL --} | ]]) - child_session = helpers.connect(child_server) + child_session = n.connect(child_server) child_session:request( 'nvim_exec2', [[ @@ -2364,14 +2475,14 @@ describe('TUI FocusGained/FocusLost', function() end) end) --- These tests require `thelpers` because --headless/--embed +-- These tests require `tt` because --headless/--embed -- does not initialize the TUI. describe("TUI 't_Co' (terminal colors)", function() local screen local function assert_term_colors(term, colorterm, maxcolors) clear({ env = { TERM = term }, args = {} }) - screen = thelpers.setup_child_nvim({ + screen = tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2647,14 +2758,14 @@ describe("TUI 't_Co' (terminal colors)", function() end) end) --- These tests require `thelpers` because --headless/--embed +-- These tests require `tt` because --headless/--embed -- does not initialize the TUI. describe("TUI 'term' option", function() local screen local function assert_term(term_envvar, term_expected) clear() - screen = thelpers.setup_child_nvim({ + screen = tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2702,7 +2813,7 @@ describe("TUI 'term' option", function() end) end) --- These tests require `thelpers` because --headless/--embed +-- These tests require `tt` because --headless/--embed -- does not initialize the TUI. describe('TUI', function() local screen @@ -2714,7 +2825,7 @@ describe('TUI', function() -- Runs (child) `nvim` in a TTY (:terminal), to start the builtin TUI. local function nvim_tui(extra_args) clear() - screen = thelpers.setup_child_nvim({ + screen = tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2795,7 +2906,7 @@ describe('TUI', function() ]]) local child_server = new_pipename() - screen = thelpers.setup_child_nvim({ + screen = tt.setup_child_nvim({ '--listen', child_server, '-u', @@ -2815,7 +2926,7 @@ describe('TUI', function() screen:expect({ any = '%[No Name%]' }) - local child_session = helpers.connect(child_server) + local child_session = n.connect(child_server) retry(nil, 1000, function() eq({ Tc = true, @@ -2845,7 +2956,7 @@ describe('TUI', function() ]]) local child_server = new_pipename() - screen = thelpers.setup_child_nvim({ + screen = tt.setup_child_nvim({ '--listen', child_server, -- Use --clean instead of -u NONE to load the osc52 plugin @@ -2861,7 +2972,7 @@ describe('TUI', function() screen:expect({ any = '%[No Name%]' }) - local child_session = helpers.connect(child_server) + local child_session = n.connect(child_server) retry(nil, 1000, function() eq('Ms', eval("get(g:, 'xtgettcap', '')")) eq({ true, 'OSC 52' }, { child_session:request('nvim_eval', 'g:clipboard.name') }) @@ -2876,7 +2987,7 @@ describe('TUI bg color', function() command('highlight clear Normal') command('set background=dark') -- set outer Nvim background local child_server = new_pipename() - local screen = thelpers.setup_child_nvim({ + local screen = tt.setup_child_nvim({ '--listen', child_server, '-u', @@ -2889,7 +3000,7 @@ describe('TUI bg color', function() 'set noswapfile', }) screen:expect({ any = '%[No Name%]' }) - local child_session = helpers.connect(child_server) + local child_session = n.connect(child_server) retry(nil, nil, function() eq({ true, 'dark' }, { child_session:request('nvim_eval', '&background') }) end) @@ -2899,7 +3010,7 @@ describe('TUI bg color', function() command('highlight clear Normal') command('set background=light') -- set outer Nvim background local child_server = new_pipename() - local screen = thelpers.setup_child_nvim({ + local screen = tt.setup_child_nvim({ '--listen', child_server, '-u', @@ -2912,7 +3023,7 @@ describe('TUI bg color', function() 'set noswapfile', }) screen:expect({ any = '%[No Name%]' }) - local child_session = helpers.connect(child_server) + local child_session = n.connect(child_server) retry(nil, nil, function() eq({ true, 'light' }, { child_session:request('nvim_eval', '&background') }) end) @@ -2930,7 +3041,7 @@ describe('TUI bg color', function() end, }) ]]) - thelpers.setup_child_nvim({ + tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2946,7 +3057,7 @@ describe('TUI bg color', function() end) it('triggers OptionSet from automatic background processing', function() - local screen = thelpers.setup_child_nvim({ + local screen = tt.setup_child_nvim({ '-u', 'NONE', '-i', @@ -2968,16 +3079,20 @@ describe('TUI bg color', function() end) end) --- These tests require `thelpers` because --headless/--embed +-- These tests require `tt` because --headless/--embed -- does not initialize the TUI. describe('TUI as a client', function() + after_each(function() + os.remove(testlog) + end) + it('connects to remote instance (with its own TUI)', function() local server_super = spawn_argv(false) -- equivalent to clear() local client_super = spawn_argv(true) set_session(server_super) local server_pipe = new_pipename() - local screen_server = thelpers.setup_child_nvim({ + local screen_server = tt.setup_child_nvim({ '--listen', server_pipe, '-u', @@ -3012,7 +3127,7 @@ describe('TUI as a client', function() } set_session(client_super) - local screen_client = thelpers.setup_child_nvim({ + local screen_client = tt.setup_child_nvim({ '--server', server_pipe, '--remote-ui', @@ -3048,7 +3163,7 @@ describe('TUI as a client', function() it('connects to remote instance (--headless)', function() local server = spawn_argv(false) -- equivalent to clear() - local client_super = spawn_argv(true) + local client_super = spawn_argv(true, { env = { NVIM_LOG_FILE = testlog } }) set_session(server) local server_pipe = api.nvim_get_vvar('servername') @@ -3056,7 +3171,7 @@ describe('TUI as a client', function() server:request('nvim_command', 'set notermguicolors') set_session(client_super) - local screen_client = thelpers.setup_child_nvim({ + local screen_client = tt.setup_child_nvim({ '--server', server_pipe, '--remote-ui', @@ -3091,11 +3206,14 @@ describe('TUI as a client', function() client_super:close() server:close() + if is_os('mac') then + assert_log('uv_tty_set_mode failed: Unknown system error %-102', testlog) + end end) it('throws error when no server exists', function() clear() - local screen = thelpers.setup_child_nvim({ + local screen = tt.setup_child_nvim({ '--server', '127.0.0.1:2436546', '--remote-ui', @@ -3116,7 +3234,7 @@ describe('TUI as a client', function() set_session(server_super) local server_pipe = new_pipename() - local screen_server = thelpers.setup_child_nvim({ + local screen_server = tt.setup_child_nvim({ '--listen', server_pipe, '-u', @@ -3160,7 +3278,7 @@ describe('TUI as a client', function() } set_session(client_super) - local screen_client = thelpers.setup_child_nvim({ + local screen_client = tt.setup_child_nvim({ '--server', server_pipe, '--remote-ui', |