aboutsummaryrefslogtreecommitdiff
path: root/test/functional/terminal/tui_spec.lua
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
commit9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch)
tree607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /test/functional/terminal/tui_spec.lua
parent9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-usermarks.tar.gz
rneovim-usermarks.tar.bz2
rneovim-usermarks.zip
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'test/functional/terminal/tui_spec.lua')
-rw-r--r--test/functional/terminal/tui_spec.lua781
1 files changed, 675 insertions, 106 deletions
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 99f69ef556..b28728057f 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -5,15 +5,15 @@
-- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
local helpers = require('test.functional.helpers')(after_each)
-local uname = helpers.uname
local thelpers = require('test.functional.terminal.helpers')
local Screen = require('test.functional.ui.screen')
-local assert_alive = helpers.assert_alive
local eq = helpers.eq
local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data
local clear = helpers.clear
local command = helpers.command
+local dedent = helpers.dedent
+local exec = helpers.exec
local testprg = helpers.testprg
local retry = helpers.retry
local nvim_prog = helpers.nvim_prog
@@ -21,16 +21,25 @@ local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
local funcs = helpers.funcs
+local meths = helpers.meths
+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 feed = helpers.feed
+local eval = helpers.eval
-if helpers.pending_win32(pending) then return end
+if helpers.skip(helpers.is_os('win')) then return end
describe('TUI', function()
local screen
local child_session
+ local child_exec_lua
before_each(function()
clear()
- local child_server = helpers.new_pipename()
+ local child_server = new_pipename()
screen = thelpers.screen_setup(0,
string.format([=[["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s laststatus=2 background=dark"]]=],
nvim_prog, child_server, nvim_set))
@@ -44,6 +53,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]])
child_session = helpers.connect(child_server)
+ child_exec_lua = thelpers.make_lua_executor(child_session)
end)
-- Wait for mode in the child Nvim (avoid "typeahead race" #10826).
@@ -66,7 +76,16 @@ describe('TUI', function()
it('rapid resize #7572 #7628', function()
-- Need buffer rows to provoke the behavior.
- feed_data(":edit test/functional/fixtures/bigfile.txt:")
+ feed_data(":edit test/functional/fixtures/bigfile.txt\n")
+ screen:expect([[
+ {1:0}000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
+ 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
+ 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
+ 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
+ {5:test/functional/fixtures/bigfile.txt }|
+ :edit test/functional/fixtures/bigfile.txt |
+ {3:-- TERMINAL --} |
+ ]])
command('call jobresize(b:terminal_job_id, 58, 9)')
command('call jobresize(b:terminal_job_id, 62, 13)')
command('call jobresize(b:terminal_job_id, 100, 42)')
@@ -83,25 +102,9 @@ describe('TUI', function()
command('call jobresize(b:terminal_job_id, 1, 4)')
screen:try_resize(57, 17)
command('call jobresize(b:terminal_job_id, 57, 17)')
- assert_alive()
- end)
-
- it('resize at startup', function()
- -- Issues: #17285 #15044 #11330
- screen:try_resize(50, 10)
- feed_command([[call termopen([v:progpath, '--clean', '--cmd', 'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile']) | sleep 500m | vs new]])
- screen:expect([[
- {1: } │ |
- {4:~ }│{4:~ }|
- {4:~ }│{4:~ }|
- {4:~ }│{4:~ }|
- {4:~ }│{4:~ }|
- {4:~ }│{5:[No Name] 0,0-1 All}|
- {4:~ }│ |
- {5:new }{MATCH:<.*[/\]nvim }|
- |
- {3:-- TERMINAL --} |
- ]])
+ retry(nil, nil, function()
+ eq({true, 57}, {child_session:request('nvim_win_get_width', 0)})
+ end)
end)
it('accepts resize while pager is active', function()
@@ -297,6 +300,199 @@ describe('TUI', function()
]], attrs)
end)
+ it('accepts mouse wheel events #19992', function()
+ child_session:request('nvim_command', [[
+ set number nostartofline nowrap mousescroll=hor:1,ver:1
+ call setline(1, repeat([join(range(10), '----')], 10))
+ vsplit
+ ]])
+ screen:expect([[
+ {11: 1 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----|
+ {11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
+ {11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelDown> in active window
+ feed_data('\027[<65;8;1M')
+ screen:expect([[
+ {11: 2 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----|
+ {11: 3 }0----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 4 }0----1----2----3----4│{11: 3 }0----1----2----3----|
+ {11: 5 }0----1----2----3----4│{11: 4 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelDown> in inactive window
+ feed_data('\027[<65;48;1M')
+ screen:expect([[
+ {11: 2 }{1:0}----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
+ {11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----|
+ {11: 5 }0----1----2----3----4│{11: 5 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelRight> in active window
+ feed_data('\027[<67;8;1M')
+ screen:expect([[
+ {11: 2 }{1:-}---1----2----3----4-│{11: 2 }0----1----2----3----|
+ {11: 3 }----1----2----3----4-│{11: 3 }0----1----2----3----|
+ {11: 4 }----1----2----3----4-│{11: 4 }0----1----2----3----|
+ {11: 5 }----1----2----3----4-│{11: 5 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelRight> in inactive window
+ feed_data('\027[<67;48;1M')
+ screen:expect([[
+ {11: 2 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4|
+ {11: 3 }----1----2----3----4-│{11: 3 }----1----2----3----4|
+ {11: 4 }----1----2----3----4-│{11: 4 }----1----2----3----4|
+ {11: 5 }----1----2----3----4-│{11: 5 }----1----2----3----4|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelDown> in active window
+ feed_data('\027[<69;8;1M')
+ screen:expect([[
+ {11: 5 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4|
+ {11: 6 }----1----2----3----4-│{11: 3 }----1----2----3----4|
+ {11: 7 }----1----2----3----4-│{11: 4 }----1----2----3----4|
+ {11: 8 }----1----2----3----4-│{11: 5 }----1----2----3----4|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelDown> in inactive window
+ feed_data('\027[<69;48;1M')
+ screen:expect([[
+ {11: 5 }{1:-}---1----2----3----4-│{11: 5 }----1----2----3----4|
+ {11: 6 }----1----2----3----4-│{11: 6 }----1----2----3----4|
+ {11: 7 }----1----2----3----4-│{11: 7 }----1----2----3----4|
+ {11: 8 }----1----2----3----4-│{11: 8 }----1----2----3----4|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelRight> in active window
+ feed_data('\027[<71;8;1M')
+ screen:expect([[
+ {11: 5 }{1:-}---6----7----8----9 │{11: 5 }----1----2----3----4|
+ {11: 6 }----6----7----8----9 │{11: 6 }----1----2----3----4|
+ {11: 7 }----6----7----8----9 │{11: 7 }----1----2----3----4|
+ {11: 8 }----6----7----8----9 │{11: 8 }----1----2----3----4|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelRight> in inactive window
+ feed_data('\027[<71;48;1M')
+ screen:expect([[
+ {11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----|
+ {11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----|
+ {11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----|
+ {11: 8 }----6----7----8----9 │{11: 8 }5----6----7----8----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelUp> in active window
+ feed_data('\027[<64;8;1M')
+ screen:expect([[
+ {11: 4 }----6----7----8----9 │{11: 5 }5----6----7----8----|
+ {11: 5 }{1:-}---6----7----8----9 │{11: 6 }5----6----7----8----|
+ {11: 6 }----6----7----8----9 │{11: 7 }5----6----7----8----|
+ {11: 7 }----6----7----8----9 │{11: 8 }5----6----7----8----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelUp> in inactive window
+ feed_data('\027[<64;48;1M')
+ screen:expect([[
+ {11: 4 }----6----7----8----9 │{11: 4 }5----6----7----8----|
+ {11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----|
+ {11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----|
+ {11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelLeft> in active window
+ feed_data('\027[<66;8;1M')
+ screen:expect([[
+ {11: 4 }5----6----7----8----9│{11: 4 }5----6----7----8----|
+ {11: 5 }5{1:-}---6----7----8----9│{11: 5 }5----6----7----8----|
+ {11: 6 }5----6----7----8----9│{11: 6 }5----6----7----8----|
+ {11: 7 }5----6----7----8----9│{11: 7 }5----6----7----8----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelLeft> in inactive window
+ feed_data('\027[<66;48;1M')
+ screen:expect([[
+ {11: 4 }5----6----7----8----9│{11: 4 }-5----6----7----8---|
+ {11: 5 }5{1:-}---6----7----8----9│{11: 5 }-5----6----7----8---|
+ {11: 6 }5----6----7----8----9│{11: 6 }-5----6----7----8---|
+ {11: 7 }5----6----7----8----9│{11: 7 }-5----6----7----8---|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelUp> in active window
+ feed_data('\027[<68;8;1M')
+ screen:expect([[
+ {11: 1 }5----6----7----8----9│{11: 4 }-5----6----7----8---|
+ {11: 2 }5----6----7----8----9│{11: 5 }-5----6----7----8---|
+ {11: 3 }5----6----7----8----9│{11: 6 }-5----6----7----8---|
+ {11: 4 }5{1:-}---6----7----8----9│{11: 7 }-5----6----7----8---|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelUp> in inactive window
+ feed_data('\027[<68;48;1M')
+ screen:expect([[
+ {11: 1 }5----6----7----8----9│{11: 1 }-5----6----7----8---|
+ {11: 2 }5----6----7----8----9│{11: 2 }-5----6----7----8---|
+ {11: 3 }5----6----7----8----9│{11: 3 }-5----6----7----8---|
+ {11: 4 }5{1:-}---6----7----8----9│{11: 4 }-5----6----7----8---|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelLeft> in active window
+ feed_data('\027[<70;8;1M')
+ screen:expect([[
+ {11: 1 }0----1----2----3----4│{11: 1 }-5----6----7----8---|
+ {11: 2 }0----1----2----3----4│{11: 2 }-5----6----7----8---|
+ {11: 3 }0----1----2----3----4│{11: 3 }-5----6----7----8---|
+ {11: 4 }0----1----2----3----{1:4}│{11: 4 }-5----6----7----8---|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelLeft> in inactive window
+ feed_data('\027[<70;48;1M')
+ screen:expect([[
+ {11: 1 }0----1----2----3----4│{11: 1 }0----1----2----3----|
+ {11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
+ {11: 4 }0----1----2----3----{1:4}│{11: 4 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
it('accepts keypad keys from kitty keyboard protocol #19180', function()
feed_data('i')
feed_data(funcs.nr2char(57399)) -- KP_0
@@ -440,37 +636,83 @@ describe('TUI', function()
tabnew
highlight Tabline ctermbg=NONE ctermfg=NONE cterm=underline
]])
- local attrs = screen:get_default_attr_ids()
- attrs[11] = {underline = true}
screen:expect([[
- {11: + [No Name] + [No Name] }{3: [No Name] }{1: }{11:X}|
+ {12: + [No Name] + [No Name] }{3: [No Name] }{1: }{12:X}|
{1: } |
{4:~ }|
{4:~ }|
{5:[No Name] }|
|
{3:-- TERMINAL --} |
- ]], attrs)
+ ]])
feed_data('\027[57421;5u') -- CTRL + KP_PAGE_UP
screen:expect([[
- {11: + [No Name] }{3: + [No Name] }{11: [No Name] }{1: }{11:X}|
+ {12: + [No Name] }{3: + [No Name] }{12: [No Name] }{1: }{12:X}|
0123456789/*-{1:+} |
= |
{4:~ }|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
- ]], attrs)
+ ]])
feed_data('\027[57422;5u') -- CTRL + KP_PAGE_DOWN
screen:expect([[
- {11: + [No Name] + [No Name] }{3: [No Name] }{1: }{11:X}|
+ {12: + [No Name] + [No Name] }{3: [No Name] }{1: }{12:X}|
{1: } |
{4:~ }|
{4:~ }|
{5:[No Name] }|
|
{3:-- TERMINAL --} |
- ]], attrs)
+ ]])
+ end)
+
+ it('mouse events work with right-click menu', function()
+ child_session:request('nvim_command', [[
+ call setline(1, 'popup menu test')
+ set mouse=a mousemodel=popup
+
+ aunmenu PopUp
+ menu PopUp.foo :let g:menustr = 'foo'<CR>
+ menu PopUp.bar :let g:menustr = 'bar'<CR>
+ menu PopUp.baz :let g:menustr = 'baz'<CR>
+ highlight Pmenu ctermbg=NONE ctermfg=NONE cterm=underline,reverse
+ highlight PmenuSel ctermbg=NONE ctermfg=NONE cterm=underline,reverse,bold
+ ]])
+ meths.input_mouse('right', 'press', '', 0, 0, 4)
+ screen:expect([[
+ {1:p}opup menu test |
+ {4:~ }{13: foo }{4: }|
+ {4:~ }{13: bar }{4: }|
+ {4:~ }{13: baz }{4: }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ meths.input_mouse('right', 'release', '', 0, 0, 4)
+ screen:expect_unchanged()
+ meths.input_mouse('move', '', '', 0, 3, 6)
+ screen:expect([[
+ {1:p}opup menu test |
+ {4:~ }{13: foo }{4: }|
+ {4:~ }{13: bar }{4: }|
+ {4:~ }{14: baz }{4: }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ meths.input_mouse('left', 'press', '', 0, 2, 6)
+ screen:expect([[
+ {1:p}opup menu test |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ :let g:menustr = 'bar' |
+ {3:-- TERMINAL --} |
+ ]])
+ meths.input_mouse('left', 'release', '', 0, 2, 6)
+ screen:expect_unchanged()
end)
it('paste: Insert mode', function()
@@ -574,12 +816,11 @@ describe('TUI', function()
end)
it('paste: terminal mode', function()
- if os.getenv('GITHUB_ACTIONS') ~= nil then
+ if is_ci('github') then
pending("tty-test complains about not owning the terminal -- actions/runner#241")
- return
end
- feed_data(':set statusline=^^^^^^^\n')
- feed_data(':terminal '..testprg('tty-test')..'\n')
+ child_exec_lua('vim.o.statusline="^^^^^^^"')
+ child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test'))
feed_data('i')
screen:expect{grid=[[
tty ready |
@@ -841,8 +1082,7 @@ describe('TUI', function()
wait_for_mode('i')
-- "bracketed paste"
feed_data('\027[200~'..expected..'\027[201~')
- -- FIXME: Data race between the two feeds
- if uname() == 'freebsd' then screen:sleep(1) end
+ expect_child_buf_lines({expected})
feed_data(' end')
expected = expected..' end'
screen:expect([[
@@ -961,6 +1201,15 @@ describe('TUI', function()
it('paste: split "start paste" code', function()
feed_data('i')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
-- Send split "start paste" sequence.
feed_data('\027[2')
feed_data('00~pasted from terminal\027[201~')
@@ -977,6 +1226,15 @@ describe('TUI', function()
it('paste: split "stop paste" code', function()
feed_data('i')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
-- Send split "stop paste" sequence.
feed_data('\027[200~pasted from terminal\027[20')
feed_data('1~')
@@ -1002,6 +1260,15 @@ describe('TUI', function()
end)(vim.paste)
]], {})
feed_data('i')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data('\027[200~pasted') -- phase 1
screen:expect([[
pasted{1: } |
@@ -1041,6 +1308,7 @@ describe('TUI', function()
[7] = {reverse = true, foreground = Screen.colors.SeaGreen4},
[8] = {foreground = Screen.colors.SeaGreen4},
[9] = {bold = true, foreground = Screen.colors.Blue1},
+ [10] = {foreground = Screen.colors.Blue},
})
feed_data(':hi SpecialKey ctermfg=3 guifg=SeaGreen\n')
@@ -1061,9 +1329,9 @@ describe('TUI', function()
feed_data(':set termguicolors\n')
screen:expect([[
{7:^}{8:G} |
- {9:~ }|
- {9:~ }|
- {9:~ }|
+ {9:~}{10: }|
+ {9:~}{10: }|
+ {9:~}{10: }|
{3:[No Name] [+] }|
:set termguicolors |
{4:-- TERMINAL --} |
@@ -1082,9 +1350,8 @@ describe('TUI', function()
end)
it('forwards :term palette colors with termguicolors', function()
- if os.getenv('GITHUB_ACTIONS') ~= nil then
+ if is_ci('github') then
pending("tty-test complains about not owning the terminal -- actions/runner#241")
- return
end
screen:set_rgb_cterm(true)
screen:set_default_attr_ids({
@@ -1095,12 +1362,9 @@ describe('TUI', function()
[5] = {{foreground = tonumber('0xff8000')}, {}},
})
- feed_data(':set statusline=^^^^^^^\n')
- feed_data(':set termguicolors\n')
- feed_data(':terminal '..testprg('tty-test')..'\n')
- -- Depending on platform the above might or might not fit in the cmdline
- -- so clear it for consistent behavior.
- feed_data(':\027')
+ child_exec_lua('vim.o.statusline="^^^^^^^"')
+ child_exec_lua('vim.o.termguicolors=true')
+ child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test'))
screen:expect{grid=[[
{1:t}ty ready |
|
@@ -1139,7 +1403,7 @@ describe('TUI', function()
|
{4:~ }|
{5: }|
- [[['chan', 0], ['height', 6], ['override', v:false|
+ [[['chan', 1], ['height', 6], ['override', v:false|
], ['rgb', v:false], ['width', 50]]] |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
@@ -1147,18 +1411,14 @@ describe('TUI', function()
end)
it('allows grid to assume wider ambiguous-width characters than host terminal #19686', function()
- child_session:request('nvim_buf_set_lines', 0, 0, 0, true, { ('℃'):rep(60), ('℃'):rep(60) })
+ child_session:request('nvim_buf_set_lines', 0, 0, -1, true, { ('℃'):rep(60), ('℃'):rep(60) })
child_session:request('nvim_win_set_option', 0, 'cursorline', true)
child_session:request('nvim_win_set_option', 0, 'list', true)
child_session:request('nvim_win_set_option', 0, 'listchars', 'eol:$')
- local attrs = screen:get_default_attr_ids()
- attrs[11] = {underline = true} -- CursorLine
- attrs[12] = {underline = true, reverse = true} -- CursorLine and TermCursor
- attrs[13] = {underline = true, foreground = 12} -- CursorLine and NonText
feed_data('gg')
local singlewidth_screen = [[
- {12:℃}{11:℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃}|
- {11:℃℃℃℃℃℃℃℃℃℃}{13:$}{11: }|
+ {13:℃}{12:℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃}|
+ {12:℃℃℃℃℃℃℃℃℃℃}{15:$}{12: }|
℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃|
℃℃℃℃℃℃℃℃℃℃{4:$} |
{5:[No Name] [+] }|
@@ -1168,23 +1428,83 @@ describe('TUI', function()
-- 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 = [[
- {12:℃}{11: ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
- {11:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
- {11:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }{13:$}{11: }|
+ {13:℃}{12: ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
+ {12:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
+ {12:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }{15:$}{12: }|
℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ >{4:@@@}|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]]
- screen:expect(singlewidth_screen, attrs)
+ screen:expect(singlewidth_screen)
child_session:request('nvim_set_option', 'ambiwidth', 'double')
- screen:expect(doublewidth_screen, attrs)
+ screen:expect(doublewidth_screen)
child_session:request('nvim_set_option', 'ambiwidth', 'single')
- screen:expect(singlewidth_screen, attrs)
+ screen:expect(singlewidth_screen)
child_session:request('nvim_call_function', 'setcellwidths', {{{0x2103, 0x2103, 2}}})
- screen:expect(doublewidth_screen, attrs)
+ screen:expect(doublewidth_screen)
child_session:request('nvim_call_function', 'setcellwidths', {{{0x2103, 0x2103, 1}}})
- screen:expect(singlewidth_screen, attrs)
+ screen:expect(singlewidth_screen)
+ end)
+
+ it('draws correctly when cursor_address overflows #21643', function()
+ helpers.skip(helpers.is_os('mac'), 'FIXME: crashes/errors on macOS')
+ screen:try_resize(77, 834)
+ retry(nil, nil, function()
+ eq({true, 831}, {child_session:request('nvim_win_get_height', 0)})
+ end)
+ -- Use full screen message so that redrawing afterwards is more deterministic.
+ child_session:notify('nvim_command', 'intro')
+ screen:expect({any = 'Nvim'})
+ -- Going to top-left corner needs 3 bytes.
+ -- Setting underline attribute needs 9 bytes.
+ -- With screen width 77, 63857 characters need 829 full screen lines.
+ -- Drawing each full screen line needs 77 + 2 = 79 bytes (2 bytes for CR LF).
+ -- The incomplete screen line needs 24 + 3 = 27 bytes.
+ -- The whole line needs 3 + 9 + 79 * 829 + 27 = 65530 bytes.
+ -- The cursor_address that comes after will overflow the 65535-byte buffer.
+ local line = ('a'):rep(63857) .. '℃'
+ child_session:notify('nvim_exec_lua', [[
+ vim.api.nvim_buf_set_lines(0, 0, -1, true, {...})
+ vim.o.cursorline = true
+ ]], {line, 'b'})
+ -- Close the :intro message and redraw the lines.
+ feed_data('\n')
+ screen:expect(
+ '{13:a}{12:' .. ('a'):rep(76) .. '}|\n'
+ .. ('{12:' .. ('a'):rep(77) .. '}|\n'):rep(828)
+ .. '{12:' .. ('a'):rep(24) .. '℃' .. (' '):rep(52) .. '}|\n' .. dedent([[
+ b |
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |]]))
+ end)
+
+ it('visual bell (padding) does not crash #21610', function()
+ feed_data ':set visualbell\n'
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ :set visualbell |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ -- move left is enough to invoke the bell
+ feed_data 'h'
+ -- visual change to show we process events after this
+ feed_data 'i'
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
end)
end)
@@ -1194,6 +1514,35 @@ describe('TUI', function()
os.remove('testF')
end)
+ it('resize at startup #17285 #15044 #11330', function()
+ local screen = Screen.new(50, 10)
+ screen:set_default_attr_ids({
+ [1] = {reverse = true},
+ [2] = {bold = true, foreground = Screen.colors.Blue},
+ [3] = {bold = true},
+ [4] = {foreground = tonumber('0x4040ff'), fg_indexed = true},
+ [5] = {bold = true, reverse = true},
+ })
+ screen:attach()
+ exec([[
+ call termopen([v:progpath, '--clean', '--cmd', 'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile'])
+ sleep 500m
+ vs new
+ ]])
+ screen:expect([[
+ ^ │ |
+ {2:~ }│{4:~ }|
+ {2:~ }│{4:~ }|
+ {2:~ }│{4:~ }|
+ {2:~ }│{4:~ }|
+ {2:~ }│{4:~ }|
+ {2:~ }│{5:[No Name] 0,0-1 All}|
+ {2:~ }│ |
+ {5:new }{MATCH:<.*[/\]nvim }|
+ |
+ ]])
+ end)
+
it('with non-tty (pipe) stdout/stderr', function()
local screen = thelpers.screen_setup(0, '"'..nvim_prog
..' -u NONE -i NONE --cmd \'set noswapfile noshowcmd noruler\' --cmd \'normal iabc\' > /dev/null 2>&1 && cat testF && rm testF"')
@@ -1212,6 +1561,15 @@ describe('TUI', function()
it('<C-h> #10134', function()
local screen = thelpers.screen_setup(0, '["'..nvim_prog
..[[", "-u", "NONE", "-i", "NONE", "--cmd", "set noruler", "--cmd", ':nnoremap <C-h> :echomsg "\<C-h\>"<CR>']]..']')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
command([[call chansend(b:terminal_job_id, "\<C-h>")]])
screen:expect([[
@@ -1238,6 +1596,15 @@ describe('TUI UIEnter/UILeave', function()
..[[, "--cmd", "autocmd VimEnter * :call add(g:evs, 'VimEnter')"]]
..']'
)
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data(":echo g:evs\n")
screen:expect{grid=[[
{1: } |
@@ -1258,61 +1625,88 @@ describe('TUI FocusGained/FocusLost', function()
clear()
screen = thelpers.screen_setup(0, '["'..nvim_prog
..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]')
- feed_data(":autocmd FocusGained * echo 'gained'\n")
- feed_data(":autocmd FocusLost * echo 'lost'\n")
- feed_data("\034\016") -- CTRL-\ CTRL-N
- end)
-
- it('in normal-mode', function()
- retry(2, 3 * screen.timeout, function()
- feed_data('\027[I')
- screen:expect([[
+ screen:expect{grid=[[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
{5:[No Name] }|
- gained |
+ |
{3:-- TERMINAL --} |
- ]])
+ ]]}
+ feed_data(":autocmd FocusGained * echo 'gained'\n")
+ feed_data(":autocmd FocusLost * echo 'lost'\n")
+ feed_data("\034\016") -- CTRL-\ CTRL-N
+ end)
- feed_data('\027[O')
- screen:expect([[
+ it('in normal-mode', function()
+ screen:expect{grid=[[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
{5:[No Name] }|
- lost |
+ :autocmd FocusLost * echo 'lost' |
{3:-- TERMINAL --} |
- ]])
+ ]]}
+ retry(2, 3 * screen.timeout, function()
+ feed_data('\027[I')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ gained |
+ {3:-- TERMINAL --} |
+ ]])
+
+ feed_data('\027[O')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ lost |
+ {3:-- TERMINAL --} |
+ ]])
end)
end)
it('in insert-mode', function()
feed_command('set noshowmode')
feed_data('i')
- retry(2, 3 * screen.timeout, function()
- feed_data('\027[I')
- screen:expect([[
- {1: } |
- {4:~ }|
- {4:~ }|
- {4:~ }|
- {5:[No Name] }|
- gained |
- {3:-- TERMINAL --} |
- ]])
- feed_data('\027[O')
- screen:expect([[
+ screen:expect{grid=[[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
{5:[No Name] }|
- lost |
+ :set noshowmode |
{3:-- TERMINAL --} |
- ]])
+ ]]}
+ retry(2, 3 * screen.timeout, function()
+ feed_data('\027[I')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ gained |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data('\027[O')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ lost |
+ {3:-- TERMINAL --} |
+ ]])
end)
end)
@@ -1349,6 +1743,15 @@ describe('TUI FocusGained/FocusLost', function()
feed_data(":autocmd!\n")
feed_data(":autocmd FocusLost * call append(line('$'), 'lost')\n")
feed_data(":autocmd FocusGained * call append(line('$'), 'gained')\n")
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
retry(2, 3 * screen.timeout, function()
-- Enter cmdline-mode.
feed_data(':')
@@ -1407,9 +1810,18 @@ describe('TUI FocusGained/FocusLost', function()
feed_data(":echom 'msg1'|echom 'msg2'|echom 'msg3'|echom 'msg4'|echom 'msg5'\n")
-- Execute :messages to provoke the press-enter prompt.
feed_data(":messages\n")
+ screen:expect{grid=[[
+ msg1 |
+ msg2 |
+ msg3 |
+ msg4 |
+ msg5 |
+ {10:Press ENTER or type command to continue}{1: } |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data('\027[I')
feed_data('\027[I')
- screen:expect([[
+ screen:expect{grid=[[
msg1 |
msg2 |
msg3 |
@@ -1417,7 +1829,7 @@ describe('TUI FocusGained/FocusLost', function()
msg5 |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
- ]])
+ ]], unchanged=true}
end)
end)
@@ -1425,7 +1837,6 @@ end)
-- does not initialize the TUI.
describe("TUI 't_Co' (terminal colors)", function()
local screen
- local is_freebsd = (uname() == 'freebsd')
local function assert_term_colors(term, colorterm, maxcolors)
helpers.clear({env={TERM=term}, args={}})
@@ -1528,7 +1939,7 @@ describe("TUI 't_Co' (terminal colors)", function()
-- which is raised to 16 by COLORTERM.
it("TERM=screen no COLORTERM uses 8/256 colors", function()
- if is_freebsd then
+ if is_os('freebsd') then
assert_term_colors("screen", nil, 256)
else
assert_term_colors("screen", nil, 8)
@@ -1536,7 +1947,7 @@ describe("TUI 't_Co' (terminal colors)", function()
end)
it("TERM=screen COLORTERM=screen uses 16/256 colors", function()
- if is_freebsd then
+ if is_os('freebsd') then
assert_term_colors("screen", "screen", 256)
else
assert_term_colors("screen", "screen", 16)
@@ -1699,8 +2110,6 @@ end)
-- does not initialize the TUI.
describe("TUI 'term' option", function()
local screen
- local is_bsd = not not string.find(uname(), 'bsd')
- local is_macos = not not string.find(uname(), 'darwin')
local function assert_term(term_envvar, term_expected)
clear()
@@ -1726,11 +2135,11 @@ describe("TUI 'term' option", function()
end)
it('gets system-provided term if $TERM is valid', function()
- if uname() == "openbsd" then
+ if is_os('openbsd') then
assert_term("xterm", "xterm")
- elseif is_bsd then -- BSD lacks terminfo, builtin is always used.
+ elseif is_os('bsd') then -- BSD lacks terminfo, builtin is always used.
assert_term("xterm", "builtin_xterm")
- elseif is_macos then
+ elseif is_os('mac') then
local status, _ = pcall(assert_term, "xterm", "xterm")
if not status then
pending("macOS: unibilium could not find terminfo")
@@ -1788,7 +2197,7 @@ describe("TUI", function()
retry(nil, 3000, function() -- Wait for log file to be flushed.
local log = read_file('Xtest_tui_verbose_log') or ''
- eq('--- Terminal info --- {{{\n', string.match(log, '%-%-%- Terminal.-\n'))
+ eq('--- Terminal info --- {{{\n', string.match(log, '%-%-%- Terminal.-\n')) -- }}}
ok(#log > 50)
end)
end)
@@ -1912,3 +2321,163 @@ describe('TUI bg color', function()
screen:expect{any='new_bg=dark'}
end)
end)
+
+-- These tests require `thelpers` because --headless/--embed
+-- does not initialize the TUI.
+describe("TUI as a client", function()
+
+ 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.screen_setup(0,
+ string.format([=[["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s laststatus=2 background=dark"]]=],
+ nvim_prog, server_pipe, nvim_set))
+
+ feed_data("iHello, World")
+ screen_server:expect{grid=[[
+ Hello, World{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
+ feed_data("\027")
+ screen_server:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ set_session(client_super)
+ local screen_client = thelpers.screen_setup(0,
+ string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ nvim_prog, server_pipe))
+
+ screen_client:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ feed_data(":q!\n")
+
+ server_super:close()
+ client_super:close()
+ end)
+
+ it("connects to remote instance (--headless)", function()
+ local server = helpers.spawn_argv(false) -- equivalent to clear()
+ local client_super = spawn_argv(true)
+
+ set_session(server)
+ local server_pipe = eval'v:servername'
+ feed'iHalloj!<esc>'
+
+ set_session(client_super)
+ local screen = thelpers.screen_setup(0,
+ string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ nvim_prog, server_pipe))
+
+ screen:expect{grid=[[
+ Halloj{1:!} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ client_super:close()
+ server:close()
+ end)
+
+
+ it("throws error when no server exists", function()
+ clear()
+ local screen = thelpers.screen_setup(0,
+ string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "127.0.0.1:2436546", "--remote-ui"]]=],
+ nvim_prog), 60)
+
+ screen:expect([[
+ Remote ui failed to start: {MATCH:.*}|
+ |
+ [Process exited 1]{1: } |
+ |
+ |
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
+ it("exits when server quits", 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.screen_setup(0,
+ string.format([=[["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s laststatus=2 background=dark"]]=],
+ nvim_prog, server_pipe, nvim_set))
+
+ feed_data("iHello, World")
+ screen_server:expect{grid=[[
+ Hello, World{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
+ feed_data("\027")
+ screen_server:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ set_session(client_super)
+ local screen_client = thelpers.screen_setup(0,
+ string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ nvim_prog, server_pipe))
+
+ screen_client:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ -- quitting the server
+ set_session(server_super)
+ feed_data(":q!\n")
+ screen_server:expect({any="Process exited 0"})
+
+ -- assert that client has exited
+ screen_client:expect({any="Process exited 0"})
+
+ server_super:close()
+ client_super:close()
+ end)
+end)