summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-05-02 22:53:45 +0100
committerBram Moolenaar <Bram@vim.org>2022-05-02 22:53:45 +0100
commitdb08887f24d20be11d184ce321bc0890613e42bd (patch)
tree6e9feb7b98be9323db3220951107c1d2edd01d57
parentf4f579b46b27f5e1689912a3e84c6a2a96efd143 (diff)
patch 8.2.4858: K_SPECIAL may be escaped twicev8.2.4858
Problem: K_SPECIAL may be escaped twice. Solution: Avoid double escaping. (closes #10340)
-rw-r--r--src/highlight.c2
-rw-r--r--src/misc2.c13
-rw-r--r--src/proto/misc2.pro4
-rw-r--r--src/term.c2
-rw-r--r--src/testdir/test_eval_stuff.vim22
-rw-r--r--src/testdir/test_feedkeys.vim11
-rw-r--r--src/testdir/test_functions.vim4
-rw-r--r--src/testdir/test_mapping.vim15
-rw-r--r--src/typval.c9
-rw-r--r--src/version.c2
10 files changed, 67 insertions, 17 deletions
diff --git a/src/highlight.c b/src/highlight.c
index 6a2b0874df..1e6f9c7066 100644
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -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
diff --git a/src/misc2.c b/src/misc2.c
index 6641a27c73..8e46a733c7 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -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;
diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro
index e34202127a..fe0a4fbb53 100644
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -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);
diff --git a/src/term.c b/src/term.c
index 4044d751a0..bf5943d53b 100644
--- a/src/term.c
+++ b/src/term.c
@@ -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;
diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim
index 6043ed9a13..3c168f2f59 100644
--- a/src/testdir/test_eval_stuff.vim
+++ b/src/testdir/test_eval_stuff.vim
@@ -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
diff --git a/src/testdir/test_feedkeys.vim b/src/testdir/test_feedkeys.vim
index f343b0174c..fb64711863 100644
--- a/src/testdir/test_feedkeys.vim
+++ b/src/testdir/test_feedkeys.vim
@@ -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
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index dbed757ff3..a1b9b3d262 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -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
diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim
index b413f4fc34..7f768cf80f 100644
--- a/src/testdir/test_mapping.vim
+++ b/src/testdir/test_mapping.vim
@@ -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
diff --git a/src/typval.c b/src/typval.c
index 50b1d620a6..4f6e41dfdd 100644
--- a/src/typval.c
+++ b/src/typval.c
@@ -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;
diff --git a/src/version.c b/src/version.c
index c62081853d..511e3d3460 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 4858,
+/**/
4857,
/**/
4856,