changeset 20727:5ffe112b1afd v8.2.0916

patch 8.2.0916: mapping with partly modifyOtherKeys code does not work Commit: https://github.com/vim/vim/commit/975a880a1389e8ce6dea8d66a7c109140b2f94ec Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jun 6 22:36:24 2020 +0200 patch 8.2.0916: mapping with partly modifyOtherKeys code does not work Problem: Mapping with partly modifyOtherKeys code does not work. Solution: If there is no mapping with a separate modifier include the modifier in the key and then try mapping again. (closes #6200)
author Bram Moolenaar <Bram@vim.org>
date Sat, 06 Jun 2020 22:45:04 +0200
parents ac788439fa5a
children 0775a4c140a9
files src/edit.c src/getchar.c src/proto/getchar.pro src/proto/term.pro src/term.c src/testdir/test_termcodes.vim src/version.c
diffstat 7 files changed, 74 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/edit.c
+++ b/src/edit.c
@@ -1609,7 +1609,7 @@ decodeModifyOtherKeys(int c)
 #endif
 
 	    mod_mask = decode_modifiers(arg[!form]);
-	    c = merge_modifyOtherKeys(arg[form]);
+	    c = merge_modifyOtherKeys(arg[form], &mod_mask);
 	}
     }
 
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -1582,15 +1582,15 @@ updatescript(int c)
 }
 
 /*
- * Convert "c" plus "mod_mask" to merge the effect of modifyOtherKeys into the
+ * Convert "c" plus "modifiers" to merge the effect of modifyOtherKeys into the
  * character.
  */
     int
-merge_modifyOtherKeys(int c_arg)
+merge_modifyOtherKeys(int c_arg, int *modifiers)
 {
     int c = c_arg;
 
-    if (mod_mask & MOD_MASK_CTRL)
+    if (*modifiers & MOD_MASK_CTRL)
     {
 	if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_'))
 	    c &= 0x1f;
@@ -1612,13 +1612,13 @@ merge_modifyOtherKeys(int c_arg)
 	    c = DEL;
 #endif
 	if (c != c_arg)
-	    mod_mask &= ~MOD_MASK_CTRL;
+	    *modifiers &= ~MOD_MASK_CTRL;
     }
-    if ((mod_mask & (MOD_MASK_META | MOD_MASK_ALT))
+    if ((*modifiers & (MOD_MASK_META | MOD_MASK_ALT))
 	    && c >= 0 && c <= 127)
     {
 	c += 0x80;
-	mod_mask &= ~(MOD_MASK_META|MOD_MASK_ALT);
+	*modifiers &= ~(MOD_MASK_META|MOD_MASK_ALT);
     }
     return c;
 }
@@ -1866,7 +1866,7 @@ vgetc(void)
 		// cases they are put back in the typeahead buffer.
 		vgetc_mod_mask = mod_mask;
 		vgetc_char = c;
-		c = merge_modifyOtherKeys(c);
+		c = merge_modifyOtherKeys(c, &mod_mask);
 	    }
 
 	    break;
@@ -2255,6 +2255,44 @@ at_ctrl_x_key(void)
 }
 
 /*
+ * Check if typebuf.tb_buf[] contains a modifer plus key that can be changed
+ * into just a key, apply that.
+ * Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off
+ * + "max_offset"].
+ * Return the length of the replaced bytes, zero if nothing changed.
+ */
+    static int
+check_simplify_modifier(int max_offset)
+{
+    int		offset;
+    char_u	*tp;
+
+    for (offset = 0; offset < max_offset; ++offset)
+    {
+	if (offset + 3 >= typebuf.tb_len)
+	    break;
+	tp = typebuf.tb_buf + typebuf.tb_off + offset;
+	if (tp[0] == K_SPECIAL && tp[1] == KS_MODIFIER)
+	{
+	    int modifier = tp[2];
+	    int new_c = merge_modifyOtherKeys(tp[3], &modifier);
+
+	    if (new_c != tp[3] && modifier == 0)
+	    {
+		char_u	new_string[MB_MAXBYTES];
+		int	len = mb_char2bytes(new_c, new_string);
+
+		if (put_string_in_typebuf(offset, 4, new_string, len,
+							   NULL, 0, 0) == FAIL)
+		    return -1;
+		return len;
+	    }
+	}
+    }
+    return 0;
+}
+
+/*
  * Handle mappings in the typeahead buffer.
  * - When something was mapped, return map_result_retry for recursive mappings.
  * - When nothing mapped and typeahead has a character: return map_result_get.
@@ -2519,6 +2557,11 @@ handle_mapping(
 	    if (keylen == 0 && save_keylen == KEYLEN_PART_KEY)
 		keylen = KEYLEN_PART_KEY;
 
+	    // If no termcode matched, try to include the modifier into the
+	    // key.  This for when modifyOtherKeys is working.
+	    if (keylen == 0)
+		keylen = check_simplify_modifier(max_mlen + 1);
+
 	    // When getting a partial match, but the last characters were not
 	    // typed, don't wait for a typed character to complete the
 	    // termcode.  This helps a lot when a ":normal" command ends in an
--- a/src/proto/getchar.pro
+++ b/src/proto/getchar.pro
@@ -37,7 +37,7 @@ void openscript(char_u *name, int direct
 void close_all_scripts(void);
 int using_script(void);
 void before_blocking(void);
-int merge_modifyOtherKeys(int c_arg);
+int merge_modifyOtherKeys(int c_arg, int *modifiers);
 int vgetc(void);
 int safe_vgetc(void);
 int plain_vgetc(void);
--- a/src/proto/term.pro
+++ b/src/proto/term.pro
@@ -68,6 +68,7 @@ int get_termcode_len(int idx);
 void del_termcode(char_u *name);
 void set_mouse_topline(win_T *wp);
 int is_mouse_topline(win_T *wp);
+int put_string_in_typebuf(int offset, int slen, char_u *string, int new_slen, char_u *buf, int bufsize, int *buflen);
 int decode_modifiers(int n);
 int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen);
 void term_get_fg_color(char_u *r, char_u *g, char_u *b);
--- a/src/term.c
+++ b/src/term.c
@@ -4251,7 +4251,7 @@ is_mouse_topline(win_T *wp)
  * Remove "slen" bytes.
  * Returns FAIL for error.
  */
-    static int
+    int
 put_string_in_typebuf(
 	int	offset,
 	int	slen,
@@ -4342,7 +4342,7 @@ modifiers2keycode(int modifiers, int *ke
 /*
  * Check if typebuf.tb_buf[] contains a terminal key code.
  * Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off
- * + max_offset].
+ * + "max_offset"].
  * Return 0 for no match, -1 for partial match, > 0 for full match.
  * Return KEYLEN_REMOVED when a key code was deleted.
  * With a match, the match is removed, the replacement code is inserted in
--- a/src/testdir/test_termcodes.vim
+++ b/src/testdir/test_termcodes.vim
@@ -1222,6 +1222,23 @@ func RunTest_mapping_shift(key, func)
   endif
 endfunc
 
+func Test_modifyOtherKeys_mapped()
+  set timeoutlen=10
+  imap ' <C-W>
+  imap <C-W><C-A> c-a
+  call setline(1, '')
+
+  " single quote is turned into single byte CTRL-W
+  " CTRL-A is added with a separate modifier, and needs to be simplified before
+  " the mapping can match.
+  call feedkeys("a'" .. GetEscCodeCSI27('A', 5) .. "\<Esc>", 'Lx!')
+  call assert_equal('c-a', getline(1))
+
+  iunmap '
+  iunmap <C-W><C-A>
+  set timeoutlen&
+endfunc
+
 func RunTest_mapping_works_with_shift(func)
   new
   set timeoutlen=10
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    916,
+/**/
     915,
 /**/
     914,