mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #18381 from zeertzjq/vim-8.2.4858
vim-patch:8.2.4858: K_SPECIAL may be escaped twice
This commit is contained in:
commit
cf474021ed
@ -4869,11 +4869,10 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
if (*p == '\\' && p[1] != NUL) {
|
if (*p == '\\' && p[1] != NUL) {
|
||||||
p++;
|
p++;
|
||||||
// A "\<x>" form occupies at least 4 characters, and produces up
|
// A "\<x>" form occupies at least 4 characters, and produces up
|
||||||
// to 21 characters (3 * 6 for the char and 3 for a modifier):
|
// to 9 characters (6 for the char and 3 for a modifier):
|
||||||
// reserve space for 18 extra.
|
// reserve space for 5 extra.
|
||||||
// Each byte in the char could be encoded as K_SPECIAL K_EXTRA x.
|
|
||||||
if (*p == '<') {
|
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] != '*') {
|
if (p[1] != '*') {
|
||||||
flags |= FSK_SIMPLIFY;
|
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) {
|
if (extra != 0) {
|
||||||
name += extra;
|
name += extra;
|
||||||
if (name >= rettv->vval.v_string + len) {
|
if (name >= rettv->vval.v_string + len) {
|
||||||
|
@ -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
|
/// @param[out] dst Location where translation result will be kept. It must
|
||||||
// be at least 19 bytes per "<x>" form.
|
// be at least 19 bytes per "<x>" form.
|
||||||
/// @param[in] flags FSK_ values
|
/// @param[in] flags FSK_ values
|
||||||
|
/// @param[in] escape_ks escape K_SPECIAL bytes in the character
|
||||||
/// @param[out] did_simplify found <C-H>, etc.
|
/// @param[out] did_simplify found <C-H>, etc.
|
||||||
///
|
///
|
||||||
/// @return Number of characters added to dst, zero for no match.
|
/// @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,
|
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
|
FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
int modifiers = 0;
|
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 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
|
/// Put the character sequence for "key" with "modifiers" into "dst" and return
|
||||||
/// the resulting length.
|
/// 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.
|
/// The sequence is not NUL terminated.
|
||||||
/// This is how characters in a string are encoded.
|
/// 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;
|
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++] = K_SPECIAL;
|
||||||
dst[dlen++] = (char_u)KEY2TERMCAP0(key);
|
dst[dlen++] = (char_u)KEY2TERMCAP0(key);
|
||||||
dst[dlen++] = KEY2TERMCAP1(key);
|
dst[dlen++] = KEY2TERMCAP1(key);
|
||||||
} else if (!keycode) {
|
} else if (escape_ks) {
|
||||||
dlen += (unsigned int)utf_char2bytes(key, dst + dlen);
|
|
||||||
} else {
|
|
||||||
char_u *after = add_char2buf(key, dst + dlen);
|
char_u *after = add_char2buf(key, dst + dlen);
|
||||||
assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX);
|
assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX);
|
||||||
dlen = (unsigned int)(after - dst);
|
dlen = (unsigned int)(after - dst);
|
||||||
|
} else {
|
||||||
|
dlen += (unsigned int)utf_char2bytes(key, dst + dlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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,
|
slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen,
|
||||||
FSK_KEYCODE | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY),
|
FSK_KEYCODE | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY),
|
||||||
did_simplify);
|
true, did_simplify);
|
||||||
if (slen) {
|
if (slen) {
|
||||||
dlen += slen;
|
dlen += slen;
|
||||||
continue;
|
continue;
|
||||||
|
@ -247,7 +247,7 @@ size_t input_enqueue(String keys)
|
|||||||
uint8_t buf[19] = { 0 };
|
uint8_t buf[19] = { 0 };
|
||||||
// Do not simplify the keys here. Simplification will be done later.
|
// Do not simplify the keys here. Simplification will be done later.
|
||||||
unsigned int new_size
|
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) {
|
if (new_size) {
|
||||||
new_size = handle_mouse_event(&ptr, buf, new_size);
|
new_size = handle_mouse_event(&ptr, buf, new_size);
|
||||||
|
@ -320,4 +320,26 @@ func Test_curly_assignment()
|
|||||||
unlet g:gvar
|
unlet g:gvar
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -23,4 +23,15 @@ func Test_feedkeys_with_abbreviation()
|
|||||||
iunabbrev trigger
|
iunabbrev trigger
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -1751,8 +1751,8 @@ func Test_nr2char()
|
|||||||
call assert_equal('a', nr2char(97, 1))
|
call assert_equal('a', nr2char(97, 1))
|
||||||
call assert_equal('a', nr2char(97, 0))
|
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" .. nr2char(0x100000), 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(0x40000000), eval('"\<M-' .. nr2char(0x40000000) .. '>"'))
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for getcurpos() and setpos()
|
" Test for getcurpos() and setpos()
|
||||||
|
@ -1025,4 +1025,19 @@ func Test_unmap_simplifiable()
|
|||||||
unmap <C-I>
|
unmap <C-I>
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -1651,10 +1651,11 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no
|
|||||||
}
|
}
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
// A "\<x>" form occupies at least 4 characters, and produces up to
|
// A "\<x>" form occupies at least 4 characters, and produces up to
|
||||||
// 6 characters: reserve space for 2 extra, but do not compute actual
|
// to 9 characters (6 for the char and 3 for a modifier):
|
||||||
// length just now, it would be costy.
|
// reserve space for 5 extra, but do not compute actual length
|
||||||
|
// just now, it would be costly.
|
||||||
case '<':
|
case '<':
|
||||||
size += 2;
|
size += 5;
|
||||||
break;
|
break;
|
||||||
// Hexadecimal, always single byte, but at least three bytes each.
|
// Hexadecimal, always single byte, but at least three bytes each.
|
||||||
case 'x':
|
case 'x':
|
||||||
@ -1822,7 +1823,7 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no
|
|||||||
flags |= FSK_SIMPLIFY;
|
flags |= FSK_SIMPLIFY;
|
||||||
}
|
}
|
||||||
const size_t special_len = trans_special((const char_u **)&p, (size_t)(e - p),
|
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) {
|
if (special_len != 0) {
|
||||||
v_p += special_len;
|
v_p += special_len;
|
||||||
} else {
|
} else {
|
||||||
|
@ -136,10 +136,17 @@ describe('mappings with <Cmd>', function()
|
|||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('handles character containing K_SPECIAL (0x80) byte correctly', function()
|
it('handles string containing K_SPECIAL (0x80) bytes correctly', function()
|
||||||
command([[noremap <F3> <Cmd>let g:str = '‥'<CR>]])
|
command([[noremap <F3> <Cmd>let g:str = 'foo…bar'<CR>]])
|
||||||
feed('<F3>')
|
feed('<F3>')
|
||||||
eq('‥', eval('g:str'))
|
eq('foo…bar', eval('g:str'))
|
||||||
|
local str = eval([["foo\<D-…>bar"]])
|
||||||
|
command([[noremap <F3> <Cmd>let g:str = ']]..str..[['<CR>]])
|
||||||
|
feed('<F3>')
|
||||||
|
eq(str, eval('g:str'))
|
||||||
|
command([[noremap <F3> <Cmd>let g:str = 'foo<D-…>bar'<CR>]])
|
||||||
|
feed('<F3>')
|
||||||
|
eq(str, eval('g:str'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('works in various modes and sees correct `mode()` value', function()
|
it('works in various modes and sees correct `mode()` value', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user