vim-patch:9.1.0580: :lmap mapping for keypad key not applied when typed in Select mode (#29693)

Problem:  An :lmap mapping for a printable keypad key is not applied
          when typing it in Select mode.
Solution: Change keypad key to ASCII after setting vgetc_char.
          (zeertzjq)

closes: vim/vim#15245

90a800274d
This commit is contained in:
zeertzjq
2024-07-14 06:50:36 +08:00
committed by GitHub
parent 1f748d46c3
commit 49ba36becd
2 changed files with 60 additions and 44 deletions

View File

@ -1634,6 +1634,50 @@ int vgetc(void)
c = TO_SPECIAL(c2, c);
}
// For a multi-byte character get all the bytes and return the
// converted character.
// Note: This will loop until enough bytes are received!
int n;
if ((n = MB_BYTE2LEN_CHECK(c)) > 1) {
no_mapping++;
buf[0] = (uint8_t)c;
for (int i = 1; i < n; i++) {
buf[i] = (uint8_t)vgetorpeek(true);
if (buf[i] == K_SPECIAL) {
// Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence,
// which represents a K_SPECIAL (0x80).
vgetorpeek(true); // skip KS_SPECIAL
vgetorpeek(true); // skip KE_FILLER
}
}
no_mapping--;
c = utf_ptr2char((char *)buf);
}
// If mappings are enabled (i.e., not i_CTRL-V) and the user directly typed
// something with MOD_MASK_ALT (<M-/<A- modifier) that was not mapped, interpret
// <M-x> as <Esc>x rather than as an unbound <M-x> keypress. #8213
// In Terminal mode, however, this is not desirable. #16202 #16220
// Also do not do this for mouse keys, as terminals encode mouse events as
// CSI sequences, and MOD_MASK_ALT has a meaning even for unmapped mouse keys.
if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT
&& !(State & MODE_TERMINAL) && !is_mouse_key(c)) {
mod_mask = 0;
int len = ins_char_typebuf(c, 0, false);
ins_char_typebuf(ESC, 0, false);
int old_len = len + 3; // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes
ungetchars(old_len);
if (on_key_buf.size >= (size_t)old_len) {
on_key_buf.size -= (size_t)old_len;
}
continue;
}
if (vgetc_char == 0) {
vgetc_mod_mask = mod_mask;
vgetc_char = c;
}
// a keypad or special function key was not mapped, use it like
// its ASCII equivalent
switch (c) {
@ -1713,50 +1757,6 @@ int vgetc(void)
c = K_RIGHT; break;
}
// For a multi-byte character get all the bytes and return the
// converted character.
// Note: This will loop until enough bytes are received!
int n;
if ((n = MB_BYTE2LEN_CHECK(c)) > 1) {
no_mapping++;
buf[0] = (uint8_t)c;
for (int i = 1; i < n; i++) {
buf[i] = (uint8_t)vgetorpeek(true);
if (buf[i] == K_SPECIAL) {
// Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence,
// which represents a K_SPECIAL (0x80).
vgetorpeek(true); // skip KS_SPECIAL
vgetorpeek(true); // skip KE_FILLER
}
}
no_mapping--;
c = utf_ptr2char((char *)buf);
}
if (vgetc_char == 0) {
vgetc_mod_mask = mod_mask;
vgetc_char = c;
}
// If mappings are enabled (i.e., not i_CTRL-V) and the user directly typed something with
// MOD_MASK_ALT (<M-/<A- modifier) that was not mapped, interpret <M-x> as <Esc>x rather
// than as an unbound <M-x> keypress. #8213
// In Terminal mode, however, this is not desirable. #16202 #16220
// Also do not do this for mouse keys, as terminals encode mouse events as CSI sequences, and
// MOD_MASK_ALT has a meaning even for unmapped mouse keys.
if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT && !(State & MODE_TERMINAL)
&& !is_mouse_key(c)) {
mod_mask = 0;
int len = ins_char_typebuf(c, 0, false);
ins_char_typebuf(ESC, 0, false);
int old_len = len + 3; // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes
ungetchars(old_len);
if (on_key_buf.size >= (size_t)old_len) {
on_key_buf.size -= (size_t)old_len;
}
continue;
}
break;
}

View File

@ -323,4 +323,20 @@ func Test_ins_ctrl_o_in_insert_mode_resets_selectmode()
bwipe!
endfunc
" Test that an :lmap mapping for a printable keypad key is applied when typing
" it in Select mode.
func Test_selectmode_keypad_lmap()
new
lnoremap <buffer> <kPoint> ???
lnoremap <buffer> <kEnter> !!!
setlocal iminsert=1
call setline(1, 'abcdef')
call feedkeys("gH\<kPoint>\<Esc>", 'tx')
call assert_equal(['???'], getline(1, '$'))
call feedkeys("gH\<kEnter>\<Esc>", 'tx')
call assert_equal(['!!!'], getline(1, '$'))
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab