From 975a880a1389e8ce6dea8d66a7c109140b2f94ec Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 6 Jun 2020 22:36:24 +0200 Subject: 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) --- src/edit.c | 2 +- src/getchar.c | 57 ++++++++++++++++++++++++++++++++++++------ src/proto/getchar.pro | 2 +- src/proto/term.pro | 1 + src/term.c | 4 +-- src/testdir/test_termcodes.vim | 17 +++++++++++++ src/version.c | 2 ++ 7 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/edit.c b/src/edit.c index 5252334ce5..dc0b45082d 100644 --- 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); } } diff --git a/src/getchar.c b/src/getchar.c index fcfad9dc0f..de814ccc68 100644 --- 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; @@ -2254,6 +2254,44 @@ at_ctrl_x_key(void) return vim_is_ctrl_x_key(c); } +/* + * 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. @@ -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 diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro index 57d78b594e..bf131a5ace 100644 --- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -37,7 +37,7 @@ void openscript(char_u *name, int directly); 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); diff --git a/src/proto/term.pro b/src/proto/term.pro index d84823cc66..88fdcb89f7 100644 --- 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); diff --git a/src/term.c b/src/term.c index b4b5c091a8..70822195b0 100644 --- 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 *key, char_u *string) /* * 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 diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index 49262f529b..86589b28d0 100644 --- 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 ' + imap 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) .. "\", 'Lx!') + call assert_equal('c-a', getline(1)) + + iunmap ' + iunmap + set timeoutlen& +endfunc + func RunTest_mapping_works_with_shift(func) new set timeoutlen=10 diff --git a/src/version.c b/src/version.c index 965877dbf0..6466000f52 100644 --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 916, /**/ 915, /**/ -- cgit v1.2.3