fix(termkey): use terminfo for (shift+)left/right keys

Problem:
Since neovim 0.12, shift + arrow keys no longer works in rxvt-unicode
(TERM=rxvt-unicode-256color).

Solution:
Re-add `left` and `right` to `wanted_termkeys` so they're read from
terminfo instead of being handled by driver-csi. There seems to be quite
a few other terminals that define kLFT in terminfo.src and these are
likely to be affected as well.

Fixes: https://github.com/neovim/neovim/issues/38571
Fixes: 4b678a499c ("refactor(termkey): make termkey use internal terminfo properly")
(cherry picked from commit c4283caa17)
This commit is contained in:
Tomas Janousek
2026-03-30 00:24:25 +01:00
committed by github-actions[bot]
parent 8e490e70ed
commit 60a24d707c
4 changed files with 42 additions and 4 deletions

View File

@@ -113,6 +113,8 @@ local wanted_termkeys = {
{ 'select', false },
{ 'suspend', true },
{ 'undo', true },
{ 'left', true },
{ 'right', true },
}
local db = '/tmp/nvim_terminfo'

View File

@@ -1,6 +1,6 @@
// uncrustify:off
// Generated by src/gen/gen_terminfo.lua and ncurses 6.5.20240427
// Generated by src/gen/gen_terminfo.lua and ncurses 6.6.20251231
#pragma once
@@ -79,6 +79,8 @@ static const TerminfoEntry ansi_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033[D", NULL},
[kTermKey_right] = {"\033[C", NULL},
},
.f_keys = {
NULL,
@@ -158,6 +160,8 @@ static const TerminfoEntry ghostty_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033OD", "\033[1;2D"},
[kTermKey_right] = {"\033OC", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -300,6 +304,8 @@ static const TerminfoEntry interix_8colour_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033[D", "\033F\136"},
[kTermKey_right] = {"\033[C", "\033F$"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -439,6 +445,8 @@ static const TerminfoEntry iterm_256colour_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033OD", "\033[1;2D"},
[kTermKey_right] = {"\033OC", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -542,6 +550,8 @@ static const TerminfoEntry linux_16colour_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {"^Z", NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033[D", NULL},
[kTermKey_right] = {"\033[C", NULL},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -641,6 +651,8 @@ static const TerminfoEntry putty_256colour_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {"^Z", NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033OD", NULL},
[kTermKey_right] = {"\033OC", NULL},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -740,6 +752,8 @@ static const TerminfoEntry rxvt_256colour_terminfo = {
[kTermKey_select] = {"\033[4~", NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033[D", "\033[d"},
[kTermKey_right] = {"\033[C", "\033[c"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -863,6 +877,8 @@ static const TerminfoEntry screen_256colour_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033OD", NULL},
[kTermKey_right] = {"\033OC", NULL},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -954,6 +970,8 @@ static const TerminfoEntry st_256colour_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033OD", "\033[1;2D"},
[kTermKey_right] = {"\033OC", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -1096,6 +1114,8 @@ static const TerminfoEntry tmux_256colour_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033OD", "\033[1;2D"},
[kTermKey_right] = {"\033OC", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -1238,6 +1258,8 @@ static const TerminfoEntry vte_256colour_terminfo = {
[kTermKey_select] = {"\033[4~", NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033OD", "\033[1;2D"},
[kTermKey_right] = {"\033OC", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -1380,6 +1402,8 @@ static const TerminfoEntry xterm_256colour_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033OD", "\033[1;2D"},
[kTermKey_right] = {"\033OC", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -1522,6 +1546,8 @@ static const TerminfoEntry cygwin_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {"^Z", NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033[D", NULL},
[kTermKey_right] = {"\033[C", NULL},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -1621,6 +1647,8 @@ static const TerminfoEntry win32con_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {"^Z", NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033[D", "\033[1;2D"},
[kTermKey_right] = {"\033[C", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -1744,6 +1772,8 @@ static const TerminfoEntry conemu_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033[D", "\033[1;2D"},
[kTermKey_right] = {"\033[C", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -1868,6 +1898,8 @@ static const TerminfoEntry vtpcon_terminfo = {
[kTermKey_select] = {NULL, NULL},
[kTermKey_suspend] = {NULL, NULL},
[kTermKey_undo] = {NULL, NULL},
[kTermKey_left] = {"\033[D", "\033[1;2D"},
[kTermKey_right] = {"\033[C", "\033[1;2C"},
},
.f_keys = {
// note: offset by one, f_keys[0] is F1 and so on
@@ -1989,6 +2021,8 @@ static const TerminfoEntry vtpcon_terminfo = {
X(select) \
Y(suspend) \
Y(undo) \
Y(left) \
Y(right) \
// end of list
#define XLIST_TERMINFO_FKEYS \

View File

@@ -77,5 +77,7 @@ typedef enum {
kTermKey_select,
kTermKey_suspend,
kTermKey_undo,
kTermKey_left,
kTermKey_right,
kTermKeyCount,
} TerminfoKey;

View File

@@ -52,7 +52,7 @@ static struct {
// { KDEF(help), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HELP, 0 },
{ KDEF(home), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 0 },
{ KDEF(ic), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT, 0 },
// { KDEF(left), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 0 }, // redundant: driver-csi
{ KDEF(left), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 0 },
// { KDEF(mark), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MARK, 0 },
// { KDEF(message), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MESSAGE, 0 },
// { KDEF(move), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MOVE, 0 },
@@ -69,12 +69,12 @@ static struct {
// { KDEF(replace), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REPLACE, 0 },
// { KDEF(restart), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RESTART, 0 },
// { KDEF(resume), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RESUME, 0 },
// { KDEF(right), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 0 }, // redundant, driver-csi
{ KDEF(right), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 0 },
// { KDEF(save), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SAVE, 0 },
{ KDEF(select), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT, 0 },
{ KDEF(suspend), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SUSPEND, 0 },
{ KDEF(undo), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UNDO, 0 },
// { KDEF(up), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 0 }, // redundant, driver-ci
// { KDEF(up), TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 0 }, // redundant, driver-csi
{ 0, NULL, 0, 0, 0 },
};