From: Hirohito Higashi Date: Fri, 31 Jul 2026 19:07:27 +0000 (+0000) Subject: patch 9.2.0888: mapping: modifier is not recognized after a partial mapping X-Git-Tag: v9.2.0888^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=62c8cdc37c2a1b3ef825022cfa343d5c16019831;p=thirdparty%2Fvim.git patch 9.2.0888: mapping: modifier is not recognized after a partial mapping Problem: With the key protocol enabled, a mapping for a key with a modifier is not used when it follows a partial match of another mapping. Solution: When the modifier was merged into the key in the typeahead, mark the key, so that the mapping for the simplified key can be used. fixes: #12002 closes: #20898 Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index 6329ac24a6..38b6ae4545 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 9.2. Last change: 2026 Jul 30 +*todo.txt* For Vim version 9.2. Last change: 2026 Jul 31 VIM REFERENCE MANUAL by Bram Moolenaar @@ -36,10 +36,6 @@ browser use: https://github.com/vim/vim/issues/1234 *known-bugs* -------------------- Known bugs and current work ----------------------- -Mapping with modifier is not recognized after a partial mapping. Probably -because the typeahead was simplified when looking for a matching mapping. -Need to somehow undo the simplification. #12002 - With 'smoothscroll' the scroll position is lost when a window is temporarily squeezed to a couple of lines, for example ":help" followed by ":close". In restore_snapshot_rec() restore more values from the snapshot, instead of diff --git a/src/getchar.c b/src/getchar.c index 83e4be3ebb..9eef2235f8 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -78,6 +78,7 @@ static int KeyNoremap = 0; // remapping flags #define RM_NONE 1 // tb_noremap: don't remap #define RM_SCRIPT 2 // tb_noremap: remap local script mappings #define RM_ABBR 4 // tb_noremap: don't remap, do abbrev. +#define RM_SIMPLIFIED 8 // tb_noremap: modifiers merged into the key // typebuf.tb_buf has three parts: room in front (for result of mappings), the // middle for typeahead and room for new characters (which needs to be 3 * @@ -2770,6 +2771,7 @@ check_simplify_modifier(int max_offset) { char_u new_string[MB_MAXBYTES]; int len; + int key_offset = offset; if (offset == 0) { @@ -2797,10 +2799,17 @@ check_simplify_modifier(int max_offset) else { tp[2] = modifier; - if (put_string_in_typebuf(offset + 3, 1, new_string, len, + key_offset = offset + 3; + if (put_string_in_typebuf(key_offset, 1, new_string, len, NULL, 0, NULL) == FAIL) return -1; } + + // A mapping for the simplified key can be used for it even + // when the key protocol is enabled. + for (int i = 0; i < len; ++i) + typebuf.tb_noremap[typebuf.tb_off + key_offset + i] + |= RM_SIMPLIFIED; return len; } } @@ -2939,7 +2948,9 @@ handle_mapping( if (mp->m_keys[0] == tb_c1 && (mp->m_mode & local_State) && !(mp->m_simplified && key_protocol_enabled() - && typebuf.tb_maplen == 0) + && typebuf.tb_maplen == 0 + && (typebuf.tb_noremap[typebuf.tb_off] + & RM_SIMPLIFIED) == 0) && ((mp->m_mode & MODE_LANGMAP) == 0 || typebuf.tb_maplen == 0)) { @@ -3002,7 +3013,7 @@ handle_mapping( // If only script-local mappings are allowed, check if the // mapping starts with K_SNR. s = typebuf.tb_noremap + typebuf.tb_off; - if (*s == RM_SCRIPT + if ((*s & ~RM_SIMPLIFIED) == RM_SCRIPT && (mp->m_keys[0] != K_SPECIAL || mp->m_keys[1] != KS_EXTRA || mp->m_keys[2] != KE_SNR)) @@ -3126,8 +3137,8 @@ handle_mapping( if (in_osc || no_mapping == 0 || allow_keys != 0) { if (in_osc || ((typebuf.tb_maplen == 0 - || (p_remap && typebuf.tb_noremap[ - typebuf.tb_off] == RM_YES)) + || (p_remap && (typebuf.tb_noremap[typebuf.tb_off] + & ~RM_SIMPLIFIED) == RM_YES)) && !*timedout)) keylen = check_termcode(max_mlen + 1, NULL, 0, NULL); else @@ -3635,7 +3646,8 @@ vgetorpeek(int advance) gotchars(typebuf.tb_buf + typebuf.tb_off, 1); } - KeyNoremap = typebuf.tb_noremap[typebuf.tb_off]; + KeyNoremap = typebuf.tb_noremap[typebuf.tb_off] + & ~RM_SIMPLIFIED; del_typebuf(1, 0); } break; // got character, break the for loop diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index adabeeedbf..a5e80d72d1 100644 --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -2298,6 +2298,30 @@ func Test_modifyOtherKeys_mapped() set timeoutlen& endfunc +func Test_modifyOtherKeys_after_partial_mapping() + new + set timeoutlen=10 + imap x + imap ab y + call setline(1, '') + + " "a" is a partial match for the "ab" mapping, CTRL-J is simplified while + " looking for that mapping and must still match the mapping. + call feedkeys("aa" .. GetEscCodeCSI27('J', 5) .. "\", 'Lx!') + call assert_equal('ax', getline(1)) + + " A NL that was not simplified from the key protocol does not use the + " mapping for CTRL-J. + %d _ + call feedkeys("aa\\", 'Lx!') + call assert_equal(['a', ''], getline(1, '$')) + + iunmap + iunmap ab + set timeoutlen& + bwipe! +endfunc + func Test_modifyOtherKeys_ambiguous_mapping() new set timeoutlen=10 diff --git a/src/version.c b/src/version.c index b3bd5174f6..0fdd61f59f 100644 --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 888, /**/ 887, /**/