fix(tui): don't treat ESC preceding repeat/release as ALT (#41770)

This commit is contained in:
zeertzjq authored and GitHub committed 2026-09-08 17:25:35 +08:00
1 parent b781e95a24
commit 03f5f25a1e
2 files changed
+28 -5

No files matched your search

+8
View File
@@ -912,6 +912,14 @@ static TermKeyResult peekkey_simple(TermKey *tk, TermKeyKey *key, int force, siz
switch (metakey_result) {
case TERMKEY_RES_KEY:
if (key->event == TERMKEY_EVENT_REPEAT || key->event == TERMKEY_EVENT_RELEASE) {
// A repeat or release event's modifiers are encoded in its escape sequence, so
// a preceding Esc cannot be its Alt modifier, and can only be an <Esc> press.
key->event = TERMKEY_EVENT_PRESS;
(*tk->method.emit_codepoint)(tk, b0, key);
*nbytep = 1;
return TERMKEY_RES_KEY;
}
key->modifiers |= TERMKEY_KEYMOD_ALT;
(*nbytep)++;
break;
+20 -5
View File
@@ -1261,17 +1261,19 @@ describe('TUI', function()
]])
end)
it('interprets leading <Esc> byte as ALT modifier in normal-mode', function()
it('interprets leading ESC byte as ALT modifier in normal-mode', function()
local keys = 'dfghjkl'
for c in keys:gmatch('.') do
feed_data(':nnoremap <a-' .. c .. '> ialt-' .. c .. '<cr><esc>\r')
feed_data('\027' .. c)
end
feed_data(':nnoremap <a-esc> ialt-esc<esc>\r')
feed_data('\027\027')
screen:expect([[
alt-j |
alt-k |
alt-l |
^ |
alt-es^c |
{3:[No Name] [+] }|
|
{5:-- TERMINAL --} |
@@ -1301,7 +1303,7 @@ describe('TUI', function()
]])
end)
it('interprets <Esc> encoded with kitty keyboard protocol', function()
it('interprets ESC encoded with kitty keyboard protocol', function()
child_session:request(
'nvim_exec2',
[[
@@ -1332,13 +1334,13 @@ describe('TUI', function()
|
{5:-- TERMINAL --} |
]])
-- <Esc>; should be recognized as <M-;> when <M-;> is mapped
-- ESC+; should be recognized as <M-;> when <M-;> is mapped
feed_data('\027;')
screen:expect_unchanged()
expect_child_buf_lines({ 'ESCsemicolonCtrlEscSuperEscESC' })
end)
it('interprets <Esc><Nul> as <M-C-Space> #17198', function()
it('interprets ESC NUL as <M-C-Space> #17198', function()
t.skip(is_os('win'), 'FIXME: does not work on Windows')
feed_data('i\022\027\000')
screen:expect([[
@@ -1350,6 +1352,19 @@ describe('TUI', function()
]])
end)
it('does not interpret ESC preceding repeat/release event as ALT #41763', function()
child_session:request('nvim_command', 'noremap <M-Esc> <Nop>')
child_session:request('nvim_command', 'noremap! <M-Esc> <Nop>')
feed_data('i\015')
wait_for_mode('niI')
feed_data('\027\027[27;1:3u') -- ESC, ESC release
wait_for_mode('i')
feed_data('\015')
wait_for_mode('niI')
feed_data('\027\027[27;1:2u\027[27;1:3u') -- ESC, ESC repeat, ESC release
wait_for_mode('n')
end)
it("split sequences work within 'ttimeoutlen' time", function()
poke_both_eventloop() -- Make sure startup requests have finished.
-- The split sequences below are always completed, so this timeout never actually fires; it only