Merge pull request #19180 from zeertzjq/tui-kitty-keypad

feat(tui): recognize keypad keys when using kitty keyboard protocol
This commit is contained in:
zeertzjq 2022-07-07 07:42:22 +08:00 committed by GitHub
commit 4cded8cec1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 459 additions and 22 deletions

View File

@ -111,11 +111,17 @@ width of the terminal.
*tui-input*
Nvim uses libtermkey to convert terminal escape sequences to key codes.
|terminfo| is used first, and CSI sequences not in |terminfo| (including
extended keys a.k.a. modifyOtherKeys or `CSI u`) can also be parsed.
extended keys a.k.a. modifyOtherKeys or "CSI u") can also be parsed.
For example, when running Nvim in tmux, this makes Nvim leave Insert mode and
go to the window below: >
tmux send-keys 'Escape' [ 2 7 u 'C-W' j
Where `'Escape' [ 2 7 u` is an unambiguous `CSI u` sequence for the <Esc> key.
tmux send-keys 'Escape' [ 2 7 u 'C-W' j
Where `'Escape' [ 2 7 u` is an unambiguous "CSI u" sequence for the <Esc> key.
The kitty keyboard protocol https://sw.kovidgoyal.net/kitty/keyboard-protocol/
is partially supported, including keypad keys in Unicode Private Use Area.
For example, this sequence is recognized by Nvim as <C-kEnter>: >
CSI 57414 ; 5 u
and can be used differently from <C-CR> in mappings.
*tui-modifyOtherKeys* *tui-csiu*
Historically, terminal emulators could not distinguish between certain control

View File

@ -1545,12 +1545,16 @@ int vgetc(void)
}
break;
case K_KUP:
case K_XUP:
c = K_UP; break;
case K_KDOWN:
case K_XDOWN:
c = K_DOWN; break;
case K_KLEFT:
case K_XLEFT:
c = K_LEFT; break;
case K_KRIGHT:
case K_XRIGHT:
c = K_RIGHT; break;
}

View File

@ -30,6 +30,8 @@
#define int_eq kh_int_hash_equal
#define handle_T_hash kh_int_hash_func
#define handle_T_eq kh_int_hash_equal
#define KittyKey_hash kh_int_hash_func
#define KittyKey_eq kh_int_hash_equal
#if defined(ARCH_64)
# define ptr_t_hash(key) uint64_t_hash((uint64_t)(key))
@ -162,6 +164,7 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2)
}
MAP_IMPL(int, int, DEFAULT_INITIALIZER)
MAP_IMPL(int, cstr_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER)
MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER)
@ -177,6 +180,8 @@ MAP_IMPL(int, String, DEFAULT_INITIALIZER)
MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER)
MAP_IMPL(KittyKey, cstr_t, DEFAULT_INITIALIZER)
/// Deletes a key:value pair from a string:pointer map, and frees the
/// storage of both key and value.
///

View File

@ -7,6 +7,7 @@
#include "nvim/extmark_defs.h"
#include "nvim/highlight_defs.h"
#include "nvim/map_defs.h"
#include "nvim/tui/input_defs.h"
#include "nvim/ui_client.h"
#if defined(__NetBSD__)
@ -34,6 +35,7 @@
// NOTE: Keys AND values must be allocated! khash.h does not make a copy.
//
MAP_DECLS(int, int)
MAP_DECLS(int, cstr_t)
MAP_DECLS(cstr_t, ptr_t)
MAP_DECLS(cstr_t, int)
MAP_DECLS(ptr_t, ptr_t)
@ -50,6 +52,8 @@ MAP_DECLS(int, String)
MAP_DECLS(ColorKey, ColorItem)
MAP_DECLS(KittyKey, cstr_t)
#define MAP_INIT { { 0, 0, 0, 0, NULL, NULL, NULL } }
#define map_init(k, v, map) do { *(map) = (Map(k, v)) MAP_INIT; } while (false)

View File

@ -23,6 +23,91 @@
#define KEY_BUFFER_SIZE 0xfff
static const struct kitty_key_map_entry {
KittyKey key;
const char *name;
} kitty_key_map_entry[] = {
{ KITTY_KEY_ESCAPE, "Esc" },
{ KITTY_KEY_ENTER, "CR" },
{ KITTY_KEY_TAB, "Tab" },
{ KITTY_KEY_BACKSPACE, "BS" },
{ KITTY_KEY_INSERT, "Insert" },
{ KITTY_KEY_DELETE, "Del" },
{ KITTY_KEY_LEFT, "Left" },
{ KITTY_KEY_RIGHT, "Right" },
{ KITTY_KEY_UP, "Up" },
{ KITTY_KEY_DOWN, "Down" },
{ KITTY_KEY_PAGE_UP, "PageUp" },
{ KITTY_KEY_PAGE_DOWN, "PageDown" },
{ KITTY_KEY_HOME, "Home" },
{ KITTY_KEY_END, "End" },
{ KITTY_KEY_F1, "F1" },
{ KITTY_KEY_F2, "F2" },
{ KITTY_KEY_F3, "F3" },
{ KITTY_KEY_F4, "F4" },
{ KITTY_KEY_F5, "F5" },
{ KITTY_KEY_F6, "F6" },
{ KITTY_KEY_F7, "F7" },
{ KITTY_KEY_F8, "F8" },
{ KITTY_KEY_F9, "F9" },
{ KITTY_KEY_F10, "F10" },
{ KITTY_KEY_F11, "F11" },
{ KITTY_KEY_F12, "F12" },
{ KITTY_KEY_F13, "F13" },
{ KITTY_KEY_F14, "F14" },
{ KITTY_KEY_F15, "F15" },
{ KITTY_KEY_F16, "F16" },
{ KITTY_KEY_F17, "F17" },
{ KITTY_KEY_F18, "F18" },
{ KITTY_KEY_F19, "F19" },
{ KITTY_KEY_F20, "F20" },
{ KITTY_KEY_F21, "F21" },
{ KITTY_KEY_F22, "F22" },
{ KITTY_KEY_F23, "F23" },
{ KITTY_KEY_F24, "F24" },
{ KITTY_KEY_F25, "F25" },
{ KITTY_KEY_F26, "F26" },
{ KITTY_KEY_F27, "F27" },
{ KITTY_KEY_F28, "F28" },
{ KITTY_KEY_F29, "F29" },
{ KITTY_KEY_F30, "F30" },
{ KITTY_KEY_F31, "F31" },
{ KITTY_KEY_F32, "F32" },
{ KITTY_KEY_F33, "F33" },
{ KITTY_KEY_F34, "F34" },
{ KITTY_KEY_F35, "F35" },
{ KITTY_KEY_KP_0, "k0" },
{ KITTY_KEY_KP_1, "k1" },
{ KITTY_KEY_KP_2, "k2" },
{ KITTY_KEY_KP_3, "k3" },
{ KITTY_KEY_KP_4, "k4" },
{ KITTY_KEY_KP_5, "k5" },
{ KITTY_KEY_KP_6, "k6" },
{ KITTY_KEY_KP_7, "k7" },
{ KITTY_KEY_KP_8, "k8" },
{ KITTY_KEY_KP_9, "k9" },
{ KITTY_KEY_KP_DECIMAL, "kPoint" },
{ KITTY_KEY_KP_DIVIDE, "kDivide" },
{ KITTY_KEY_KP_MULTIPLY, "kMultiply" },
{ KITTY_KEY_KP_SUBTRACT, "kMinus" },
{ KITTY_KEY_KP_ADD, "kPlus" },
{ KITTY_KEY_KP_ENTER, "kEnter" },
{ KITTY_KEY_KP_EQUAL, "kEqual" },
{ KITTY_KEY_KP_LEFT, "kLeft" },
{ KITTY_KEY_KP_RIGHT, "kRight" },
{ KITTY_KEY_KP_UP, "kUp" },
{ KITTY_KEY_KP_DOWN, "kDown" },
{ KITTY_KEY_KP_PAGE_UP, "kPageUp" },
{ KITTY_KEY_KP_PAGE_DOWN, "kPageDown" },
{ KITTY_KEY_KP_HOME, "kHome" },
{ KITTY_KEY_KP_END, "kEnd" },
{ KITTY_KEY_KP_INSERT, "kInsert" },
{ KITTY_KEY_KP_DELETE, "kDel" },
{ KITTY_KEY_KP_BEGIN, "kOrigin" },
};
static Map(KittyKey, cstr_t) kitty_key_map = MAP_INIT;
#ifndef UNIT_TESTING
typedef enum {
kIncomplete = -1,
@ -50,6 +135,11 @@ void tinput_init(TermInput *input, Loop *loop)
uv_mutex_init(&input->key_buffer_mutex);
uv_cond_init(&input->key_buffer_cond);
for (size_t i = 0; i < ARRAY_SIZE(kitty_key_map_entry); i++) {
map_put(KittyKey, cstr_t)(&kitty_key_map, kitty_key_map_entry[i].key,
kitty_key_map_entry[i].name);
}
// If stdin is not a pty, switch to stderr. For cases like:
// echo q | nvim -es
// ls *.md | xargs nvim
@ -89,6 +179,7 @@ void tinput_init(TermInput *input, Loop *loop)
void tinput_destroy(TermInput *input)
{
map_destroy(KittyKey, cstr_t)(&kitty_key_map);
rbuffer_free(input->key_buffer);
uv_mutex_destroy(&input->key_buffer_mutex);
uv_cond_destroy(&input->key_buffer_cond);
@ -206,19 +297,46 @@ static void tinput_enqueue(TermInput *input, char *buf, size_t size)
rbuffer_write(input->key_buffer, buf, size);
}
static void handle_kitty_key_protocol(TermInput *input, TermKeyKey *key)
{
const char *name = map_get(KittyKey, cstr_t)(&kitty_key_map, (KittyKey)key->code.codepoint);
if (name) {
char buf[64];
size_t len = 0;
buf[len++] = '<';
if (key->modifiers & TERMKEY_KEYMOD_SHIFT) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "S-");
}
if (key->modifiers & TERMKEY_KEYMOD_ALT) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "A-");
}
if (key->modifiers & TERMKEY_KEYMOD_CTRL) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "C-");
}
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "%s>", name);
tinput_enqueue(input, buf, len);
}
}
static void forward_simple_utf8(TermInput *input, TermKeyKey *key)
{
size_t len = 0;
char buf[64];
char *ptr = key->utf8;
while (*ptr) {
if (*ptr == '<') {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "<lt>");
} else {
buf[len++] = *ptr;
if (key->code.codepoint >= 0xE000 && key->code.codepoint <= 0xF8FF
&& map_has(KittyKey, cstr_t)(&kitty_key_map, (KittyKey)key->code.codepoint)) {
handle_kitty_key_protocol(input, key);
return;
} else {
while (*ptr) {
if (*ptr == '<') {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "<lt>");
} else {
buf[len++] = *ptr;
}
ptr++;
}
ptr++;
}
tinput_enqueue(input, buf, len);
@ -236,19 +354,26 @@ static void forward_modified_utf8(TermInput *input, TermKeyKey *key)
len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
} else {
assert(key->modifiers);
// Termkey doesn't include the S- modifier for ASCII characters (e.g.,
// ctrl-shift-l is <C-L> instead of <C-S-L>. Vim, on the other hand,
// treats <C-L> and <C-l> the same, requiring the S- modifier.
len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
if ((key->modifiers & TERMKEY_KEYMOD_CTRL)
&& !(key->modifiers & TERMKEY_KEYMOD_SHIFT)
&& ASCII_ISUPPER(key->code.codepoint)) {
assert(len <= 62);
// Make room for the S-
memmove(buf + 3, buf + 1, len - 1);
buf[1] = 'S';
buf[2] = '-';
len += 2;
if (key->code.codepoint >= 0xE000 && key->code.codepoint <= 0xF8FF
&& map_has(KittyKey, cstr_t)(&kitty_key_map,
(KittyKey)key->code.codepoint)) {
handle_kitty_key_protocol(input, key);
return;
} else {
// Termkey doesn't include the S- modifier for ASCII characters (e.g.,
// ctrl-shift-l is <C-L> instead of <C-S-L>. Vim, on the other hand,
// treats <C-L> and <C-l> the same, requiring the S- modifier.
len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
if ((key->modifiers & TERMKEY_KEYMOD_CTRL)
&& !(key->modifiers & TERMKEY_KEYMOD_SHIFT)
&& ASCII_ISUPPER(key->code.codepoint)) {
assert(len <= 62);
// Make room for the S-
memmove(buf + 3, buf + 1, len - 1);
buf[1] = 'S';
buf[2] = '-';
len += 2;
}
}
}

View File

@ -6,6 +6,7 @@
#include "nvim/event/stream.h"
#include "nvim/event/time.h"
#include "nvim/tui/input_defs.h"
#include "nvim/tui/tui.h"
typedef enum {

118
src/nvim/tui/input_defs.h Normal file
View File

@ -0,0 +1,118 @@
#ifndef NVIM_TUI_INPUT_DEFS_H
#define NVIM_TUI_INPUT_DEFS_H
typedef enum {
KITTY_KEY_ESCAPE = 57344,
KITTY_KEY_ENTER = 57345,
KITTY_KEY_TAB = 57346,
KITTY_KEY_BACKSPACE = 57347,
KITTY_KEY_INSERT = 57348,
KITTY_KEY_DELETE = 57349,
KITTY_KEY_LEFT = 57350,
KITTY_KEY_RIGHT = 57351,
KITTY_KEY_UP = 57352,
KITTY_KEY_DOWN = 57353,
KITTY_KEY_PAGE_UP = 57354,
KITTY_KEY_PAGE_DOWN = 57355,
KITTY_KEY_HOME = 57356,
KITTY_KEY_END = 57357,
KITTY_KEY_CAPS_LOCK = 57358,
KITTY_KEY_SCROLL_LOCK = 57359,
KITTY_KEY_NUM_LOCK = 57360,
KITTY_KEY_PRINT_SCREEN = 57361,
KITTY_KEY_PAUSE = 57362,
KITTY_KEY_MENU = 57363,
KITTY_KEY_F1 = 57364,
KITTY_KEY_F2 = 57365,
KITTY_KEY_F3 = 57366,
KITTY_KEY_F4 = 57367,
KITTY_KEY_F5 = 57368,
KITTY_KEY_F6 = 57369,
KITTY_KEY_F7 = 57370,
KITTY_KEY_F8 = 57371,
KITTY_KEY_F9 = 57372,
KITTY_KEY_F10 = 57373,
KITTY_KEY_F11 = 57374,
KITTY_KEY_F12 = 57375,
KITTY_KEY_F13 = 57376,
KITTY_KEY_F14 = 57377,
KITTY_KEY_F15 = 57378,
KITTY_KEY_F16 = 57379,
KITTY_KEY_F17 = 57380,
KITTY_KEY_F18 = 57381,
KITTY_KEY_F19 = 57382,
KITTY_KEY_F20 = 57383,
KITTY_KEY_F21 = 57384,
KITTY_KEY_F22 = 57385,
KITTY_KEY_F23 = 57386,
KITTY_KEY_F24 = 57387,
KITTY_KEY_F25 = 57388,
KITTY_KEY_F26 = 57389,
KITTY_KEY_F27 = 57390,
KITTY_KEY_F28 = 57391,
KITTY_KEY_F29 = 57392,
KITTY_KEY_F30 = 57393,
KITTY_KEY_F31 = 57394,
KITTY_KEY_F32 = 57395,
KITTY_KEY_F33 = 57396,
KITTY_KEY_F34 = 57397,
KITTY_KEY_F35 = 57398,
KITTY_KEY_KP_0 = 57399,
KITTY_KEY_KP_1 = 57400,
KITTY_KEY_KP_2 = 57401,
KITTY_KEY_KP_3 = 57402,
KITTY_KEY_KP_4 = 57403,
KITTY_KEY_KP_5 = 57404,
KITTY_KEY_KP_6 = 57405,
KITTY_KEY_KP_7 = 57406,
KITTY_KEY_KP_8 = 57407,
KITTY_KEY_KP_9 = 57408,
KITTY_KEY_KP_DECIMAL = 57409,
KITTY_KEY_KP_DIVIDE = 57410,
KITTY_KEY_KP_MULTIPLY = 57411,
KITTY_KEY_KP_SUBTRACT = 57412,
KITTY_KEY_KP_ADD = 57413,
KITTY_KEY_KP_ENTER = 57414,
KITTY_KEY_KP_EQUAL = 57415,
KITTY_KEY_KP_SEPARATOR = 57416,
KITTY_KEY_KP_LEFT = 57417,
KITTY_KEY_KP_RIGHT = 57418,
KITTY_KEY_KP_UP = 57419,
KITTY_KEY_KP_DOWN = 57420,
KITTY_KEY_KP_PAGE_UP = 57421,
KITTY_KEY_KP_PAGE_DOWN = 57422,
KITTY_KEY_KP_HOME = 57423,
KITTY_KEY_KP_END = 57424,
KITTY_KEY_KP_INSERT = 57425,
KITTY_KEY_KP_DELETE = 57426,
KITTY_KEY_KP_BEGIN = 57427,
KITTY_KEY_MEDIA_PLAY = 57428,
KITTY_KEY_MEDIA_PAUSE = 57429,
KITTY_KEY_MEDIA_PLAY_PAUSE = 57430,
KITTY_KEY_MEDIA_REVERSE = 57431,
KITTY_KEY_MEDIA_STOP = 57432,
KITTY_KEY_MEDIA_FAST_FORWARD = 57433,
KITTY_KEY_MEDIA_REWIND = 57434,
KITTY_KEY_MEDIA_TRACK_NEXT = 57435,
KITTY_KEY_MEDIA_TRACK_PREVIOUS = 57436,
KITTY_KEY_MEDIA_RECORD = 57437,
KITTY_KEY_LOWER_VOLUME = 57438,
KITTY_KEY_RAISE_VOLUME = 57439,
KITTY_KEY_MUTE_VOLUME = 57440,
KITTY_KEY_LEFT_SHIFT = 57441,
KITTY_KEY_LEFT_CONTROL = 57442,
KITTY_KEY_LEFT_ALT = 57443,
KITTY_KEY_LEFT_SUPER = 57444,
KITTY_KEY_LEFT_HYPER = 57445,
KITTY_KEY_LEFT_META = 57446,
KITTY_KEY_RIGHT_SHIFT = 57447,
KITTY_KEY_RIGHT_CONTROL = 57448,
KITTY_KEY_RIGHT_ALT = 57449,
KITTY_KEY_RIGHT_SUPER = 57450,
KITTY_KEY_RIGHT_HYPER = 57451,
KITTY_KEY_RIGHT_META = 57452,
KITTY_KEY_ISO_LEVEL3_SHIFT = 57453,
KITTY_KEY_ISO_LEVEL5_SHIFT = 57454,
} KittyKey;
#endif // NVIM_TUI_INPUT_DEFS_H

View File

@ -20,6 +20,7 @@ local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
local funcs = helpers.funcs
if helpers.pending_win32(pending) then return end
@ -297,6 +298,179 @@ describe('TUI', function()
]], attrs)
end)
it('accepts keypad keys from kitty keyboard protocol #19180', function()
feed_data('i')
feed_data(funcs.nr2char(57399)) -- KP_0
feed_data(funcs.nr2char(57400)) -- KP_1
feed_data(funcs.nr2char(57401)) -- KP_2
feed_data(funcs.nr2char(57402)) -- KP_3
feed_data(funcs.nr2char(57403)) -- KP_4
feed_data(funcs.nr2char(57404)) -- KP_5
feed_data(funcs.nr2char(57405)) -- KP_6
feed_data(funcs.nr2char(57406)) -- KP_7
feed_data(funcs.nr2char(57407)) -- KP_8
feed_data(funcs.nr2char(57408)) -- KP_9
feed_data(funcs.nr2char(57409)) -- KP_DECIMAL
feed_data(funcs.nr2char(57410)) -- KP_DIVIDE
feed_data(funcs.nr2char(57411)) -- KP_MULTIPLY
feed_data(funcs.nr2char(57412)) -- KP_SUBTRACT
feed_data(funcs.nr2char(57413)) -- KP_ADD
feed_data(funcs.nr2char(57414)) -- KP_ENTER
feed_data(funcs.nr2char(57415)) -- KP_EQUAL
screen:expect([[
0123456789./*-+ |
={1: } |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]])
feed_data(funcs.nr2char(57417)) -- KP_LEFT
screen:expect([[
0123456789./*-+ |
{1:=} |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]])
feed_data(funcs.nr2char(57418)) -- KP_RIGHT
screen:expect([[
0123456789./*-+ |
={1: } |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]])
feed_data(funcs.nr2char(57419)) -- KP_UP
screen:expect([[
0{1:1}23456789./*-+ |
= |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]])
feed_data(funcs.nr2char(57420)) -- KP_DOWN
screen:expect([[
0123456789./*-+ |
={1: } |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]])
feed_data(funcs.nr2char(57425)) -- KP_INSERT
screen:expect([[
0123456789./*-+ |
={1: } |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
{3:-- REPLACE --} |
{3:-- TERMINAL --} |
]])
feed_data('\027[27u') -- ESC
screen:expect([[
0123456789./*-+ |
{1:=} |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
feed_data('\027[57417;5u') -- CTRL + KP_LEFT
screen:expect([[
{1:0}123456789./*-+ |
= |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
feed_data('\027[57418;2u') -- SHIFT + KP_RIGHT
screen:expect([[
0123456789{1:.}/*-+ |
= |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
feed_data(funcs.nr2char(57426)) -- KP_DELETE
screen:expect([[
0123456789{1:/}*-+ |
= |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
feed_data(funcs.nr2char(57423)) -- KP_HOME
screen:expect([[
{1:0}123456789/*-+ |
= |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
feed_data(funcs.nr2char(57424)) -- KP_END
screen:expect([[
0123456789/*-{1:+} |
= |
{4:~ }|
{4:~ }|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
feed_data(':tab split\r:tabnew\r')
feed_data(':highlight Tabline ctermbg=NONE ctermfg=NONE cterm=underline\r')
local attrs = screen:get_default_attr_ids()
attrs[11] = {underline = true}
screen:expect([[
{11: + [No Name] + [No Name] }{3: [No Name] }{1: }{11: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}|
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}|
{1: } |
{4:~ }|
{4:~ }|
{5:[No Name] }|
|
{3:-- TERMINAL --} |
]], attrs)
end)
it('paste: Insert mode', function()
-- "bracketed paste"
feed_data('i""\027i\027[200~')