diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c index ef067f68e2..9827604d67 100644 --- a/src/nvim/keycodes.c +++ b/src/nvim/keycodes.c @@ -850,7 +850,8 @@ char *vim_strsave_escape_ks(char *p) /// Remove escaping from K_SPECIAL characters. Reverse of /// vim_strsave_escape_ks(). Works in-place. -void vim_unescape_ks(char *p) +/// Returns the number of bytes in the unescaped string. +size_t vim_unescape_ks(char *p) { uint8_t *s = (uint8_t *)p; uint8_t *d = (uint8_t *)p; @@ -864,4 +865,5 @@ void vim_unescape_ks(char *p) } } *d = NUL; + return (size_t)((char *)d - p); } diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index a922d42b1f..3bebbb62eb 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -628,29 +628,28 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, // vi-compatible way. int same = -1; - const char *p = lhs; - const char *p_char = mb_unescape(&p); - if (p_char == NULL) { - p_char = p++; - } - const int first = vim_iswordp(p_char); + char keys_unescaped[MAXMAPLEN + 1]; + xmemcpyz(keys_unescaped, lhs, (size_t)len); + size_t keys_unescaped_len = vim_unescape_ks(keys_unescaped); + const char *p = keys_unescaped; + + const int first = vim_iswordp(p); int last = first; + MB_PTR_ADV(p); int n = 1; - while (p < lhs + len) { + while (p < keys_unescaped + keys_unescaped_len) { n++; // nr of (multi-byte) chars - p_char = mb_unescape(&p); - if (p_char == NULL) { - p_char = p++; - } - last = vim_iswordp(p_char); // type of last char + last = vim_iswordp(p); // type of last char if (same == -1 && last != first) { same = n - 1; // count of same char type } + MB_PTR_ADV(p); } if (last && n > 2 && same >= 0 && same < n - 1) { retval = 1; goto theend; } + // An abbreviation cannot contain white space. for (n = 0; n < len; n++) { if (ascii_iswhite(lhs[n])) { @@ -1537,8 +1536,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol) if (strchr(mp->m_keys, K_SPECIAL) != NULL) { // Might have K_SPECIAL escaped mp->m_keys. q = xstrdup(mp->m_keys); - vim_unescape_ks(q); - qlen = (int)strlen(q); + qlen = (int)vim_unescape_ks(q); } // find entries with right mode and keys int match = (mp->m_mode & State) diff --git a/test/old/testdir/test_mapping.vim b/test/old/testdir/test_mapping.vim index 78ff9850ab..5505d0f4d4 100644 --- a/test/old/testdir/test_mapping.vim +++ b/test/old/testdir/test_mapping.vim @@ -30,6 +30,18 @@ func Test_abbreviation() iunab abc; iunab ; + " abbreviation with composing chars (end-id) + inoreab ..ã a^~ + inoreab ..β̃ β^~ + inoreab ..π̃ π^~ + inoreab ..Λ̃ Λ^~ + call feedkeys("Go..ã ..β̃ ..π̃ ..Λ̃ \", "xt") + call assert_equal('a^~ β^~ π^~ Λ^~ ', getline('$')) + iunab ..ã + iunab ..β̃ + iunab ..π̃ + iunab ..Λ̃ + bwipe! endfunc