Commit: patch 9.2.0888: mapping: modifier is not recognized after a partial mapping

Christian Brabandt <[email protected]> Fri, 31 Jul 2026 21:15:06 +0200
Newsgroups gmane.editors.vim.devel
Message-ID <[email protected]>
patch 9.2.0888: mapping: modifier is not recognized after a partial mapping

Commit: https://github.com/vim/vim/commit/62c8cdc37c2a1b3ef825022cfa343d5c16019831
Author: Hirohito Higashi <[email protected]>
Date:   Fri Jul 31 19:07:27 2026 +0000

    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) <[email protected]>
    Signed-off-by: Hirohito Higashi <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 6329ac24a..38b6ae454 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 83e4be3eb..9eef2235f 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 adabeeedb..a5e80d72d 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 <C-J> 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 <C-J> mapping.
+  call feedkeys("aa" .. GetEscCodeCSI27('J', 5) .. "\<Esc>", '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\<C-J>\<Esc>", 'Lx!')
+  call assert_equal(['a', ''], getline(1, '$'))
+
+  iunmap <C-J>
+  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 b3bd5174f..0fdd61f59 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,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wpshG-006GkJ-TZ%40256bit.org.