test(tui_spec): prevent race between nvim_input and nvim_paste (#27356)

This commit is contained in:
zeertzjq
2024-02-06 14:05:49 +08:00
committed by GitHub
parent f6042d5c30
commit d6fac187f1
2 changed files with 78 additions and 142 deletions

View File

@@ -97,18 +97,19 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
[1] = { reverse = true }, -- focused cursor [1] = { reverse = true }, -- focused cursor
[2] = { background = 11 }, -- unfocused cursor [2] = { background = 11 }, -- unfocused cursor
[3] = { bold = true }, [3] = { bold = true },
[4] = { foreground = 12 }, [4] = { foreground = 12 }, -- NonText in :terminal session
[5] = { bold = true, reverse = true }, [5] = { bold = true, reverse = true },
-- 6 was a duplicate item [6] = { foreground = 81 }, -- SpecialKey in :terminal session
[7] = { foreground = 130 }, [7] = { foreground = 130 }, -- LineNr in host session
[8] = { foreground = 15, background = 1 }, -- error message [8] = { foreground = 15, background = 1 }, -- ErrorMsg in :terminal session
[9] = { foreground = 4 }, [9] = { foreground = 4 },
[10] = { foreground = 121 }, -- "Press ENTER" in embedded :terminal session. [10] = { foreground = 121 }, -- MoreMsg in :terminal session
[11] = { foreground = tonumber('0x00000b') }, [11] = { foreground = 11 }, -- LineNr in :terminal session
[12] = { underline = true }, [12] = { underline = true },
[13] = { underline = true, reverse = true }, [13] = { underline = true, reverse = true },
[14] = { underline = true, reverse = true, bold = true }, [14] = { underline = true, reverse = true, bold = true },
[15] = { underline = true, foreground = 12 }, [15] = { underline = true, foreground = 12 },
[16] = { background = 248, foreground = 0 }, -- Visual in :terminal session
}) })
screen:attach(screen_opts or { rgb = false }) screen:attach(screen_opts or { rgb = false })

View File

@@ -338,18 +338,13 @@ describe('TUI', function()
feed_data('\022\007') -- ctrl+g feed_data('\022\007') -- ctrl+g
feed_data('\022\022') -- ctrl+v feed_data('\022\022') -- ctrl+v
feed_data('\022\013') -- ctrl+m feed_data('\022\013') -- ctrl+m
local attrs = screen:get_default_attr_ids() screen:expect([[
attrs[11] = { foreground = 81 } {6:^G^V^M}{1: } |
screen:expect(
[[
{11:^G^V^M}{1: } |
{4:~ }|*3 {4:~ }|*3
{5:[No Name] [+] }| {5:[No Name] [+] }|
{3:-- INSERT --} | {3:-- INSERT --} |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
attrs
)
end) end)
local function test_mouse_wheel(esc) local function test_mouse_wheel(esc)
@@ -978,8 +973,7 @@ describe('TUI', function()
it('paste: select-mode', function() it('paste: select-mode', function()
feed_data('ithis is line 1\nthis is line 2\nline 3 is here\n\027') feed_data('ithis is line 1\nthis is line 2\nline 3 is here\n\027')
wait_for_mode('n') wait_for_mode('n')
screen:expect { screen:expect([[
grid = [[
this is line 1 | this is line 1 |
this is line 2 | this is line 2 |
line 3 is here | line 3 is here |
@@ -987,24 +981,29 @@ describe('TUI', function()
{5:[No Name] [+] }| {5:[No Name] [+] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
-- Select-mode. Use <C-n> to move down. -- Select-mode. Use <C-n> to move down.
feed_data('gg04lgh\14\14') feed_data('gg04lgh\14\14')
wait_for_mode('s') screen:expect([[
this{16: is line 1} |
{16:this is line 2} |
{16:line}{1: }3 is here |
|
{5:[No Name] [+] }|
{3:-- SELECT --} |
{3:-- TERMINAL --} |
]])
feed_data('\027[200~') feed_data('\027[200~')
feed_data('just paste it™') feed_data('just paste it™')
feed_data('\027[201~') feed_data('\027[201~')
screen:expect { screen:expect([[
grid = [[
thisjust paste it{1:™}3 is here | thisjust paste it{1:™}3 is here |
| |
{4:~ }|*2 {4:~ }|*2
{5:[No Name] [+] }| {5:[No Name] [+] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
-- Undo. -- Undo.
feed_data('u') feed_data('u')
expect_child_buf_lines { expect_child_buf_lines {
@@ -1028,27 +1027,23 @@ describe('TUI', function()
child_exec_lua('vim.o.statusline="^^^^^^^"') child_exec_lua('vim.o.statusline="^^^^^^^"')
child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test')) child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test'))
feed_data('i') feed_data('i')
screen:expect { screen:expect([[
grid = [[
tty ready | tty ready |
{1: } | {1: } |
|*2 |*2
{5:^^^^^^^ }| {5:^^^^^^^ }|
{3:-- TERMINAL --} |*2 {3:-- TERMINAL --} |*2
]], ]])
}
feed_data('\027[200~') feed_data('\027[200~')
feed_data('hallo') feed_data('hallo')
feed_data('\027[201~') feed_data('\027[201~')
screen:expect { screen:expect([[
grid = [[
tty ready | tty ready |
hallo{1: } | hallo{1: } |
|*2 |*2
{5:^^^^^^^ }| {5:^^^^^^^ }|
{3:-- TERMINAL --} |*2 {3:-- TERMINAL --} |*2
]], ]])
}
end) end)
it('paste: normal-mode (+CRLF #10872)', function() it('paste: normal-mode (+CRLF #10872)', function()
@@ -1060,38 +1055,27 @@ describe('TUI', function()
local expected_crlf = { 'line 1', 'ESC:\027 / CR: ', 'x' } local expected_crlf = { 'line 1', 'ESC:\027 / CR: ', 'x' }
local expected_grid1 = [[ local expected_grid1 = [[
line 1 | line 1 |
ESC:{11:^[} / CR: | ESC:{6:^[} / CR: |
{1:x} | {1:x} |
{4:~ }| {4:~ }|
{5:[No Name] [+] 3,1 All}| {5:[No Name] [+] 3,1 All}|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]] ]]
local expected_attr = {
[1] = { reverse = true },
[3] = { bold = true },
[4] = { foreground = tonumber('0x00000c') },
[5] = { bold = true, reverse = true },
[11] = { foreground = tonumber('0x000051') },
[12] = { reverse = true, foreground = tonumber('0x000051') },
}
-- "bracketed paste" -- "bracketed paste"
feed_data('\027[200~' .. table.concat(expected_lf, '\n') .. '\027[201~') feed_data('\027[200~' .. table.concat(expected_lf, '\n') .. '\027[201~')
screen:expect { grid = expected_grid1, attr_ids = expected_attr } screen:expect(expected_grid1)
-- Dot-repeat/redo. -- Dot-repeat/redo.
feed_data('.') feed_data('.')
screen:expect { screen:expect([[
grid = [[ ESC:{6:^[} / CR: |
ESC:{11:^[} / CR: |
xline 1 | xline 1 |
ESC:{11:^[} / CR: | ESC:{6:^[} / CR: |
{1:x} | {1:x} |
{5:[No Name] [+] 5,1 Bot}| {5:[No Name] [+] 5,1 Bot}|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
attr_ids = expected_attr,
}
-- Undo. -- Undo.
feed_data('u') feed_data('u')
expect_child_buf_lines(expected_crlf) expect_child_buf_lines(expected_crlf)
@@ -1103,7 +1087,7 @@ describe('TUI', function()
wait_for_mode('n') wait_for_mode('n')
-- CRLF input -- CRLF input
feed_data('\027[200~' .. table.concat(expected_lf, '\r\n') .. '\027[201~') feed_data('\027[200~' .. table.concat(expected_lf, '\r\n') .. '\027[201~')
screen:expect { grid = expected_grid1, attr_ids = expected_attr } screen:expect(expected_grid1)
expect_child_buf_lines(expected_crlf) expect_child_buf_lines(expected_crlf)
end) end)
@@ -1112,35 +1096,39 @@ describe('TUI', function()
feed_data('\027:""') -- Enter Cmdline-mode. feed_data('\027:""') -- Enter Cmdline-mode.
feed_data('\027[D') -- <Left> to place cursor between quotes. feed_data('\027[D') -- <Left> to place cursor between quotes.
wait_for_mode('c') wait_for_mode('c')
screen:expect([[
foo |
|
{4:~ }|*2
{5:[No Name] [+] }|
:"{1:"} |
{3:-- TERMINAL --} |
]])
-- "bracketed paste" -- "bracketed paste"
feed_data('\027[200~line 1\nline 2\n') feed_data('\027[200~line 1\nline 2\n')
wait_for_mode('c') wait_for_mode('c')
feed_data('line 3\nline 4\n\027[201~') feed_data('line 3\nline 4\n\027[201~')
wait_for_mode('c') wait_for_mode('c')
screen:expect { screen:expect([[
grid = [[
foo | foo |
| |
{4:~ }|*2 {4:~ }|*2
{5:[No Name] [+] }| {5:[No Name] [+] }|
:"line 1{1:"} | :"line 1{1:"} |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
-- Dot-repeat/redo. -- Dot-repeat/redo.
feed_data('\027[27u') feed_data('\027[27u')
wait_for_mode('n') wait_for_mode('n')
feed_data('.') feed_data('.')
screen:expect { screen:expect([[
grid = [[
foo |*2 foo |*2
{1: } | {1: } |
{4:~ }| {4:~ }|
{5:[No Name] [+] }| {5:[No Name] [+] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
end) end)
it('paste: cmdline-mode collects chunks of unfinished line', function() it('paste: cmdline-mode collects chunks of unfinished line', function()
@@ -1148,11 +1136,13 @@ describe('TUI', function()
retry(nil, nil, function() retry(nil, nil, function()
local _, cmdline = child_session:request('nvim_call_function', 'getcmdline', {}) local _, cmdline = child_session:request('nvim_call_function', 'getcmdline', {})
eq(expected, cmdline) eq(expected, cmdline)
local _, pos = child_session:request('nvim_call_function', 'getcmdpos', {})
eq(#expected, pos) -- Cursor is just before the last char.
end) end)
end end
feed_data('\027:""') -- Enter Cmdline-mode. feed_data('\027:""') -- Enter Cmdline-mode.
feed_data('\027[D') -- <Left> to place cursor between quotes. feed_data('\027[D') -- <Left> to place cursor between quotes.
wait_for_mode('c') expect_cmdline('""')
feed_data('\027[200~stuff 1 ') feed_data('\027[200~stuff 1 ')
expect_cmdline('"stuff 1 "') expect_cmdline('"stuff 1 "')
-- Discards everything after the first line. -- Discards everything after the first line.
@@ -1180,20 +1170,17 @@ describe('TUI', function()
-- Prepare something for dot-repeat/redo. -- Prepare something for dot-repeat/redo.
feed_data('ifoo\n\027[27u') feed_data('ifoo\n\027[27u')
wait_for_mode('n') wait_for_mode('n')
screen:expect { screen:expect([[
grid = [[
foo | foo |
{1: } | {1: } |
{4:~ }|*2 {4:~ }|*2
{5:[No Name] [+] }| {5:[No Name] [+] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
-- Start pasting... -- Start pasting...
feed_data('\027[200~line 1\nline 2\n') feed_data('\027[200~line 1\nline 2\n')
screen:expect { screen:expect([[
grid = [[
foo | foo |
| |
{5: }| {5: }|
@@ -1201,52 +1188,39 @@ describe('TUI', function()
{8:ake fail} | {8:ake fail} |
{10:Press ENTER or type command to continue}{1: } | {10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
-- Remaining chunks are discarded after vim.paste() failure. -- Remaining chunks are discarded after vim.paste() failure.
feed_data('line 3\nline 4\n') feed_data('line 3\nline 4\n')
feed_data('line 5\nline 6\n') feed_data('line 5\nline 6\n')
feed_data('line 7\nline 8\n') feed_data('line 7\nline 8\n')
-- Stop paste. -- Stop paste.
feed_data('\027[201~') feed_data('\027[201~')
feed_data('\n') -- <CR> feed_data('\n') -- <CR> to dismiss hit-enter prompt
expect_child_buf_lines({ 'foo', '' }) expect_child_buf_lines({ 'foo', '' })
--Dot-repeat/redo is not modified by failed paste. -- Dot-repeat/redo is not modified by failed paste.
feed_data('.') feed_data('.')
screen:expect { screen:expect([[
grid = [[
foo |*2 foo |*2
{1: } | {1: } |
{4:~ }| {4:~ }|
{5:[No Name] [+] }| {5:[No Name] [+] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
-- Editor should still work after failed/drained paste. -- Editor should still work after failed/drained paste.
feed_data('ityped input...\027[27u') feed_data('ityped input...\027[27u')
screen:expect { screen:expect([[
grid = [[
foo |*2 foo |*2
typed input..{1:.} | typed input..{1:.} |
{4:~ }| {4:~ }|
{5:[No Name] [+] }| {5:[No Name] [+] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
-- Paste works if vim.paste() succeeds. -- Paste works if vim.paste() succeeds.
child_session:request( child_session:request('nvim_exec_lua', [[vim.paste = _G.save_paste_fn]], {})
'nvim_exec_lua',
[[
vim.paste = _G.save_paste_fn
]],
{}
)
feed_data('\027[200~line A\nline B\n\027[201~') feed_data('\027[200~line A\nline B\n\027[201~')
feed_data('\n') -- <CR> screen:expect([[
screen:expect {
grid = [[
foo | foo |
typed input...line A | typed input...line A |
line B | line B |
@@ -1254,8 +1228,7 @@ describe('TUI', function()
{5:[No Name] [+] }| {5:[No Name] [+] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
end) end)
it('paste: vim.paste() cancel (retval=false) #10865', function() it('paste: vim.paste() cancel (retval=false) #10865', function()
@@ -1284,8 +1257,7 @@ describe('TUI', function()
{} {}
) )
feed_data('\027[200~fail 1\nfail 2\n\027[201~') feed_data('\027[200~fail 1\nfail 2\n\027[201~')
screen:expect { screen:expect([[
grid = [[
| |
{4:~ }| {4:~ }|
{5: }| {5: }|
@@ -1293,13 +1265,11 @@ describe('TUI', function()
{8:hanges, 'modifiable' is off} | {8:hanges, 'modifiable' is off} |
{10:Press ENTER or type command to continue}{1: } | {10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
} feed_data('\n') -- <Enter> to dismiss hit-enter prompt
feed_data('\n') -- <Enter>
child_session:request('nvim_command', 'set modifiable') child_session:request('nvim_command', 'set modifiable')
feed_data('\027[200~success 1\nsuccess 2\n\027[201~') feed_data('\027[200~success 1\nsuccess 2\n\027[201~')
screen:expect { screen:expect([[
grid = [[
success 1 | success 1 |
success 2 | success 2 |
{1: } | {1: } |
@@ -1307,8 +1277,7 @@ describe('TUI', function()
{5:[No Name] [+] }| {5:[No Name] [+] }|
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
end) end)
it('paste: exactly 64 bytes #10311', function() it('paste: exactly 64 bytes #10311', function()
@@ -1337,15 +1306,13 @@ describe('TUI', function()
wait_for_mode('c') wait_for_mode('c')
-- "bracketed paste" -- "bracketed paste"
feed_data('\027[200~' .. expected .. '\027[201~') feed_data('\027[200~' .. expected .. '\027[201~')
screen:expect { screen:expect([[
grid = [[
| |
{4:~ }|*3 {4:~ }|*3
{5:[No Name] }| {5:[No Name] }|
:<{1: } | :<{1: } |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
}
end) end)
it('paste: big burst of input', function() it('paste: big burst of input', function()
@@ -1387,9 +1354,10 @@ describe('TUI', function()
it('paste: forwards spurious "start paste" code', function() it('paste: forwards spurious "start paste" code', function()
-- If multiple "start paste" sequences are sent without a corresponding -- If multiple "start paste" sequences are sent without a corresponding
-- "stop paste" sequence, only the first occurrence should be consumed. -- "stop paste" sequence, only the first occurrence should be consumed.
feed_data('i')
wait_for_mode('i')
-- Send the "start paste" sequence. -- Send the "start paste" sequence.
feed_data('i\027[200~') feed_data('\027[200~')
feed_data('\npasted from terminal (1)\n') feed_data('\npasted from terminal (1)\n')
-- Send spurious "start paste" sequence. -- Send spurious "start paste" sequence.
feed_data('\027[200~') feed_data('\027[200~')
@@ -1397,8 +1365,7 @@ describe('TUI', function()
-- Send the "stop paste" sequence. -- Send the "stop paste" sequence.
feed_data('\027[201~') feed_data('\027[201~')
screen:expect { screen:expect([[
grid = [[
| |
pasted from terminal (1) | pasted from terminal (1) |
{6:^[}[200~ | {6:^[}[200~ |
@@ -1406,22 +1373,14 @@ describe('TUI', function()
{5:[No Name] [+] }| {5:[No Name] [+] }|
{3:-- INSERT --} | {3:-- INSERT --} |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]])
attr_ids = {
[1] = { reverse = true },
[2] = { background = tonumber('0x00000b') },
[3] = { bold = true },
[4] = { foreground = tonumber('0x00000c') },
[5] = { bold = true, reverse = true },
[6] = { foreground = tonumber('0x000051') },
},
}
end) end)
it('paste: ignores spurious "stop paste" code', function() it('paste: ignores spurious "stop paste" code', function()
-- If "stop paste" sequence is received without a preceding "start paste" -- If "stop paste" sequence is received without a preceding "start paste"
-- sequence, it should be ignored. -- sequence, it should be ignored.
feed_data('i') feed_data('i')
wait_for_mode('i')
-- Send "stop paste" sequence. -- Send "stop paste" sequence.
feed_data('\027[201~') feed_data('\027[201~')
screen:expect([[ screen:expect([[
@@ -1435,15 +1394,7 @@ describe('TUI', function()
it('paste: split "start paste" code', function() it('paste: split "start paste" code', function()
feed_data('i') feed_data('i')
screen:expect { wait_for_mode('i')
grid = [[
{1: } |
{4:~ }|*3
{5:[No Name] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]],
}
-- Send split "start paste" sequence. -- Send split "start paste" sequence.
feed_data('\027[2') feed_data('\027[2')
feed_data('00~pasted from terminal\027[201~') feed_data('00~pasted from terminal\027[201~')
@@ -1458,15 +1409,7 @@ describe('TUI', function()
it('paste: split "stop paste" code', function() it('paste: split "stop paste" code', function()
feed_data('i') feed_data('i')
screen:expect { wait_for_mode('i')
grid = [[
{1: } |
{4:~ }|*3
{5:[No Name] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]],
}
-- Send split "stop paste" sequence. -- Send split "stop paste" sequence.
feed_data('\027[200~pasted from terminal\027[20') feed_data('\027[200~pasted from terminal\027[20')
feed_data('1~') feed_data('1~')
@@ -1494,15 +1437,7 @@ describe('TUI', function()
{} {}
) )
feed_data('i') feed_data('i')
screen:expect { wait_for_mode('i')
grid = [[
{1: } |
{4:~ }|*3
{5:[No Name] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]],
}
feed_data('\027[200~pasted') -- phase 1 feed_data('\027[200~pasted') -- phase 1
screen:expect([[ screen:expect([[
pasted{1: } | pasted{1: } |