diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-05-03 06:11:22 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2022-05-03 06:21:50 +0800 |
commit | 27149e0071c3fa38c81526f63a997bedfd6e2be8 (patch) | |
tree | 8d819a934bd5c11c7947ff06bea23a609723d078 | |
parent | ddf7bb24f98b468d2bc6c16c6f300570fc6530f5 (diff) | |
download | rneovim-27149e0071c3fa38c81526f63a997bedfd6e2be8.tar.gz rneovim-27149e0071c3fa38c81526f63a997bedfd6e2be8.tar.bz2 rneovim-27149e0071c3fa38c81526f63a997bedfd6e2be8.zip |
vim-patch:8.2.4858: K_SPECIAL may be escaped twice
Problem: K_SPECIAL may be escaped twice.
Solution: Avoid double escaping. (closes vim/vim#10340)
https://github.com/vim/vim/commit/db08887f24d20be11d184ce321bc0890613e42bd
-rw-r--r-- | src/nvim/eval.c | 9 | ||||
-rw-r--r-- | src/nvim/keymap.c | 17 | ||||
-rw-r--r-- | src/nvim/os/input.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_eval_stuff.vim | 22 | ||||
-rw-r--r-- | src/nvim/testdir/test_feedkeys.vim | 11 | ||||
-rw-r--r-- | src/nvim/testdir/test_functions.vim | 4 | ||||
-rw-r--r-- | src/nvim/testdir/test_mapping.vim | 15 | ||||
-rw-r--r-- | src/nvim/viml/parser/expressions.c | 9 |
8 files changed, 69 insertions, 20 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index da869df5cc..3023b1e774 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4869,11 +4869,10 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) if (*p == '\\' && p[1] != NUL) { 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; } } } @@ -4971,7 +4970,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) if (p[1] != '*') { flags |= FSK_SIMPLIFY; } - extra = trans_special((const char_u **)&p, STRLEN(p), name, flags, NULL); + extra = trans_special((const char_u **)&p, STRLEN(p), name, flags, false, NULL); if (extra != 0) { name += extra; if (name >= rettv->vval.v_string + len) { diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index db51237771..7541837782 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -569,11 +569,12 @@ char_u *get_special_key_name(int c, int modifiers) /// @param[out] dst Location where translation result will be kept. It must // be at least 19 bytes per "<x>" form. /// @param[in] flags FSK_ values +/// @param[in] escape_ks escape K_SPECIAL bytes in the character /// @param[out] did_simplify found <C-H>, etc. /// /// @return Number of characters added to dst, zero for no match. unsigned int trans_special(const char_u **const srcp, const size_t src_len, char_u *const dst, - const int flags, bool *const did_simplify) + const int flags, const bool escape_ks, bool *const did_simplify) FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT { int modifiers = 0; @@ -582,15 +583,15 @@ unsigned int trans_special(const char_u **const srcp, const size_t src_len, char 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. -unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst) +unsigned int special_to_buf(int key, int modifiers, bool escape_ks, char_u *dst) { unsigned int dlen = 0; @@ -605,12 +606,12 @@ unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst) dst[dlen++] = K_SPECIAL; dst[dlen++] = (char_u)KEY2TERMCAP0(key); dst[dlen++] = KEY2TERMCAP1(key); - } else if (!keycode) { - dlen += (unsigned int)utf_char2bytes(key, dst + dlen); - } else { + } else if (escape_ks) { char_u *after = add_char2buf(key, dst + dlen); assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX); dlen = (unsigned int)(after - dst); + } else { + dlen += (unsigned int)utf_char2bytes(key, dst + dlen); } return dlen; @@ -943,7 +944,7 @@ char_u *replace_termcodes(const char_u *const from, const size_t from_len, char_ slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, FSK_KEYCODE | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY), - did_simplify); + true, did_simplify); if (slen) { dlen += slen; continue; diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 9ee2f57b3d..437baf0e08 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -247,7 +247,7 @@ size_t input_enqueue(String keys) uint8_t buf[19] = { 0 }; // Do not simplify the keys here. Simplification will be done later. unsigned int new_size - = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, FSK_KEYCODE, NULL); + = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, FSK_KEYCODE, true, NULL); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim index 95eccde35c..811c6c946d 100644 --- a/src/nvim/testdir/test_eval_stuff.vim +++ b/src/nvim/testdir/test_eval_stuff.vim @@ -320,4 +320,26 @@ func Test_curly_assignment() unlet g:gvar 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/nvim/testdir/test_feedkeys.vim b/src/nvim/testdir/test_feedkeys.vim index f343b0174c..fb64711863 100644 --- a/src/nvim/testdir/test_feedkeys.vim +++ b/src/nvim/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/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index f8be250f73..87606f17b8 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1751,8 +1751,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 getcurpos() and setpos() diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index 1da3b71a32..752b1700d0 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -1025,4 +1025,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/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 29d686193d..01fc282891 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -1651,10 +1651,11 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no } switch (*p) { // A "\<x>" form occupies at least 4 characters, and produces up to - // 6 characters: reserve space for 2 extra, but do not compute actual - // length just now, it would be costy. + // to 9 characters (6 for the char and 3 for a modifier): + // reserve space for 5 extra, but do not compute actual length + // just now, it would be costly. case '<': - size += 2; + size += 5; break; // Hexadecimal, always single byte, but at least three bytes each. case 'x': @@ -1822,7 +1823,7 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no flags |= FSK_SIMPLIFY; } const size_t special_len = trans_special((const char_u **)&p, (size_t)(e - p), - (char_u *)v_p, flags, NULL); + (char_u *)v_p, flags, false, NULL); if (special_len != 0) { v_p += special_len; } else { |