patch 8.2.4858: K_SPECIAL may be escaped twice v8.2.4858
authorzeertzjq <zeertzjq@outlook.com>
Mon, 2 May 2022 21:53:45 +0000 (22:53 +0100)
committerBram Moolenaar <Bram@vim.org>
Mon, 2 May 2022 21:53:45 +0000 (22:53 +0100)
Problem:    K_SPECIAL may be escaped twice.
Solution:   Avoid double escaping. (closes #10340)

src/highlight.c
src/misc2.c
src/proto/misc2.pro
src/term.c
src/testdir/test_eval_stuff.vim
src/testdir/test_feedkeys.vim
src/testdir/test_functions.vim
src/testdir/test_mapping.vim
src/typval.c
src/version.c

index 6a2b0874df9265f778d06706539ef427d73d53c4..1e6f9c70666bfd79a80f5f7d2dbd5e682aa3440f 100644 (file)
@@ -1356,7 +1356,7 @@ highlight_set_startstop_termcode(int idx, char_u *key, char_u *arg, int init)
        // Copy characters from arg[] to buf[], translating <> codes.
        for (p = arg, off = 0; off < 100 - 6 && *p; )
        {
-           len = trans_special(&p, buf + off, FSK_SIMPLIFY, NULL);
+           len = trans_special(&p, buf + off, FSK_SIMPLIFY, FALSE, NULL);
            if (len > 0)            // recognized special char
                off += len;
            else                    // copy as normal char
index 6641a27c73a2681da57fab4ca54dc23c9190e7e6..8e46a733c7d850ee1d29836bd9c528551c6926c2 100644 (file)
@@ -1265,6 +1265,7 @@ trans_special(
     char_u     **srcp,
     char_u     *dst,
     int                flags,          // FSK_ values
+    int                escape_ks,      // escape K_SPECIAL bytes in the character
     int                *did_simplify)  // FSK_SIMPLIFY and found <C-H> or <A-x>
 {
     int                modifiers = 0;
@@ -1274,18 +1275,18 @@ trans_special(
     if (key == 0)
        return 0;
 
-    return special_to_buf(key, modifiers, flags & FSK_KEYCODE, dst);
+    return special_to_buf(key, modifiers, escape_ks, dst);
 }
 
 /*
  * Put the character sequence for "key" with "modifiers" into "dst" and return
  * the resulting length.
- * When "keycode" is TRUE prefer key code, e.g. K_DEL instead of DEL.
+ * When "escape_ks" is TRUE escape K_SPECIAL bytes in the character.
  * The sequence is not NUL terminated.
  * This is how characters in a string are encoded.
  */
     int
-special_to_buf(int key, int modifiers, int keycode, char_u *dst)
+special_to_buf(int key, int modifiers, int escape_ks, char_u *dst)
 {
     int                dlen = 0;
 
@@ -1303,10 +1304,10 @@ special_to_buf(int key, int modifiers, int keycode, char_u *dst)
        dst[dlen++] = KEY2TERMCAP0(key);
        dst[dlen++] = KEY2TERMCAP1(key);
     }
-    else if (has_mbyte && !keycode)
-       dlen += (*mb_char2bytes)(key, dst + dlen);
-    else if (keycode)
+    else if (escape_ks)
        dlen = (int)(add_char2buf(key, dst + dlen) - dst);
+    else if (has_mbyte)
+       dlen += (*mb_char2bytes)(key, dst + dlen);
     else
        dst[dlen++] = key;
 
index e34202127ac91259841e8e3c197cbd4c8313162d..fe0a4fbb53883214451bd99c7ffca99b48c4695a 100644 (file)
@@ -24,8 +24,8 @@ int vim_isspace(int x);
 int simplify_key(int key, int *modifiers);
 int handle_x_keys(int key);
 char_u *get_special_key_name(int c, int modifiers);
-int trans_special(char_u **srcp, char_u *dst, int flags, int *did_simplify);
-int special_to_buf(int key, int modifiers, int keycode, char_u *dst);
+int trans_special(char_u **srcp, char_u *dst, int flags, int escape_ks, int *did_simplify);
+int special_to_buf(int key, int modifiers, int escape_ks, char_u *dst);
 int find_special_key(char_u **srcp, int *modp, int flags, int *did_simplify);
 int may_adjust_key_for_ctrl(int modifiers, int key);
 int may_remove_shift_modifier(int modifiers, int key);
index 4044d751a0e72fb1078738fa93551023f715d2a1..bf5943d53b582c83d25002b2955438178783df65 100644 (file)
@@ -6104,7 +6104,7 @@ replace_termcodes(
 #endif
            slen = trans_special(&src, result + dlen, FSK_KEYCODE
                          | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY),
-                                                                did_simplify);
+                                                          TRUE, did_simplify);
            if (slen)
            {
                dlen += slen;
index 6043ed9a135b433828ea4df16372bdbf506f9fc7..3c168f2f59b58599dd68c262a83e472838c08c43 100644 (file)
@@ -595,4 +595,26 @@ func Test_deep_recursion()
   call assert_fails("exe 'if ' .. repeat('(', 1002)", 'E1169: Expression too recursive: ((')
 endfunc
 
+" K_SPECIAL in the modified character used be escaped, which causes
+" double-escaping with feedkeys() or as the return value of an <expr> mapping,
+" and doesn't match what getchar() returns,
+func Test_modified_char_no_escape_special()
+  nnoremap <M-…> <Cmd>let g:got_m_ellipsis += 1<CR>
+  call feedkeys("\<M-…>", 't')
+  call assert_equal("\<M-…>", getchar())
+  let g:got_m_ellipsis = 0
+  call feedkeys("\<M-…>", 'xt')
+  call assert_equal(1, g:got_m_ellipsis)
+  func Func()
+    return "\<M-…>"
+  endfunc
+  nmap <expr> <F2> Func()
+  call feedkeys("\<F2>", 'xt')
+  call assert_equal(2, g:got_m_ellipsis)
+  delfunc Func
+  nunmap <F2>
+  unlet g:got_m_ellipsis
+  nunmap <M-…>
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index f343b0174cad0ef5401e2273acba1be356d0b61f..fb64711863050844aaeadd0c2c725f14c3d28595 100644 (file)
@@ -23,4 +23,15 @@ func Test_feedkeys_with_abbreviation()
   iunabbrev trigger
 endfunc
 
+func Test_feedkeys_escape_special()
+  nnoremap … <Cmd>let g:got_ellipsis += 1<CR>
+  call feedkeys('…', 't')
+  call assert_equal('…', getcharstr())
+  let g:got_ellipsis = 0
+  call feedkeys('…', 'xt')
+  call assert_equal(1, g:got_ellipsis)
+  unlet g:got_ellipsis
+  nunmap …
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index dbed757ff3a968c9f0f493b5c2a1934974939c7d..a1b9b3d2620023ab266a471d5b643119426b6673 100644 (file)
@@ -2721,8 +2721,8 @@ func Test_nr2char()
   call assert_equal('a', nr2char(97, 1))
   call assert_equal('a', nr2char(97, 0))
 
-  call assert_equal("\x80\xfc\b\xf4\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x100000) .. '>"'))
-  call assert_equal("\x80\xfc\b\xfd\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x40000000) .. '>"'))
+  call assert_equal("\x80\xfc\b" .. nr2char(0x100000), eval('"\<M-' .. nr2char(0x100000) .. '>"'))
+  call assert_equal("\x80\xfc\b" .. nr2char(0x40000000), eval('"\<M-' .. nr2char(0x40000000) .. '>"'))
 endfunc
 
 " Test for screenattr(), screenchar() and screenchars() functions
index b413f4fc345b8efa590e59dc22a14ecb352f811f..7f768cf80f74de59b6bd44d21d0c2c23c5c56026 100644 (file)
@@ -1643,4 +1643,19 @@ func Test_unmap_simplifiable()
   unmap <C-I>
 endfunc
 
+func Test_expr_map_escape_special()
+  nnoremap … <Cmd>let g:got_ellipsis += 1<CR>
+  func Func()
+    return '…'
+  endfunc
+  nmap <expr> <F2> Func()
+  let g:got_ellipsis = 0
+  call feedkeys("\<F2>", 'xt')
+  call assert_equal(1, g:got_ellipsis)
+  delfunc Func
+  nunmap <F2>
+  unlet g:got_ellipsis
+  nunmap …
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 50b1d620a6d3f882506cf548a06849510298c138..4f6e41dfdd6c99709225e9c72863bb1bddfd13e9 100644 (file)
@@ -2069,11 +2069,10 @@ eval_string(char_u **arg, typval_T *rettv, int evaluate)
        {
            ++p;
            // A "\<x>" form occupies at least 4 characters, and produces up
-           // to 21 characters (3 * 6 for the char and 3 for a modifier):
-           // reserve space for 18 extra.
-           // Each byte in the char could be encoded as K_SPECIAL K_EXTRA x.
+           // to 9 characters (6 for the char and 3 for a modifier):
+           // reserve space for 5 extra.
            if (*p == '<')
-               extra += 18;
+               extra += 5;
        }
     }
 
@@ -2168,7 +2167,7 @@ eval_string(char_u **arg, typval_T *rettv, int evaluate)
 
                              if (p[1] != '*')
                                  flags |= FSK_SIMPLIFY;
-                             extra = trans_special(&p, end, flags, NULL);
+                             extra = trans_special(&p, end, flags, FALSE, NULL);
                              if (extra != 0)
                              {
                                  end += extra;
index c62081853d1903303dc202d676aab4d6fd80126a..511e3d346011748ea30c233489d08fe422e66510 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4858,
 /**/
     4857,
 /**/