vim-patch:8.2.0855: GUI tests fail because the test doesn't use a modifier

Problem:    GUI tests fail because the test doesn't use a modifier.
Solution:   Add "\{xxx}" to be able to encode a modifier.
ebe9d34aa0

Change macros to enums to use them in unit tests.
This commit is contained in:
zeertzjq 2022-04-26 15:05:56 +08:00
parent 6832b626ea
commit abe91e1efe
12 changed files with 83 additions and 56 deletions

View File

@ -1325,6 +1325,9 @@ A string constant accepts these special characters:
To use the double quote character it must be escaped: "<M-\">".
Don't use <Char-xxxx> to get a UTF-8 character, use \uxxxx as
mentioned above.
\{xxx} like \<xxx> but prepends a modifier instead of including it in the
character. E.g. "\<C-w>" is one character 0x17 while "\{C-w}" is four
bytes: 3 for the CTRL modifier and then character "W".
Note that "\xff" is stored as the byte 255, which may be invalid in some
encodings. Use "\u00ff" to store character 255 correctly as UTF-8.

View File

@ -4963,9 +4963,17 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
++name;
break;
// Special key, e.g.: "\<C-W>"
// Special key, e.g.: "\<C-W>" or "\{C-W}"
case '<':
extra = trans_special((const char_u **)&p, STRLEN(p), name, true, true, true, NULL);
case '{': {
int flags = FSK_KEYCODE | FSK_IN_STRING;
if (*p == '<') {
flags |= FSK_SIMPLIFY;
} else {
flags |= FSK_CURLY;
}
extra = trans_special((const char_u **)&p, STRLEN(p), name, flags, NULL);
if (extra != 0) {
name += extra;
if (name >= rettv->vval.v_string + len) {
@ -4973,6 +4981,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
}
break;
}
}
FALLTHROUGH;
default:

View File

@ -568,25 +568,21 @@ char_u *get_special_key_name(int c, int modifiers)
/// @param[in] src_len Length of the srcp.
/// @param[out] dst Location where translation result will be kept. It must
// be at least 19 bytes per "<x>" form.
/// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL.
/// @param[in] in_string Inside a double quoted string
/// @param[in] simplify simplify <C-H>, etc.
/// @param[in] flags FSK_ values
/// @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 bool keycode, const bool in_string, const bool simplify,
bool *const did_simplify)
const int flags, bool *const did_simplify)
FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
int modifiers = 0;
int key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string, simplify,
did_simplify);
int key = find_special_key(srcp, src_len, &modifiers, flags, did_simplify);
if (key == 0) {
return 0;
}
return special_to_buf(key, modifiers, keycode, dst);
return special_to_buf(key, modifiers, flags & FSK_KEYCODE, dst);
}
/// Put the character sequence for "key" with "modifiers" into "dst" and return
@ -625,16 +621,12 @@ unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst)
/// @param[in,out] srcp Translated <> name. Is advanced to after the <> name.
/// @param[in] src_len srcp length.
/// @param[out] modp Location where information about modifiers is saved.
/// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL.
/// @param[in] keep_x_key Dont translate xHome to Home key.
/// @param[in] in_string In string, double quote is escaped
/// @param[in] simplify simplify <C-H>, etc.
/// @param[out] did_simplify found <C-H>, etc.
/// @param[in] flags FSK_ values
/// @param[out] did_simplify FSK_SIMPLIFY and found <C-H>, etc.
///
/// @return Key and modifiers or 0 if there is no match.
int find_special_key(const char_u **const srcp, const size_t src_len, int *const modp,
const bool keycode, const bool keep_x_key, const bool in_string,
const bool simplify, bool *const did_simplify)
const int flags, bool *const did_simplify)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3)
{
const char_u *last_dash;
@ -642,9 +634,11 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const
const char_u *src;
const char_u *bp;
const char_u *const end = *srcp + src_len - 1;
const bool in_string = flags & FSK_IN_STRING;
int modifiers;
int bit;
int key;
const int endchar = (flags & FSK_CURLY) ? '}' : '>';
uvarnumber_T n;
int l;
@ -653,7 +647,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const
}
src = *srcp;
if (src[0] != '<') {
if (src[0] != ((flags & FSK_CURLY) ? '{' : '<')) {
return 0;
}
@ -667,16 +661,16 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const
// Anything accepted, like <C-?>.
// <C-"> or <M-"> are not special in strings as " is
// the string delimiter. With a backslash it works: <M-\">
if (end - bp > l && !(in_string && bp[1] == '"') && bp[l+1] == '>') {
if (end - bp > l && !(in_string && bp[1] == '"') && bp[l + 1] == endchar) {
bp += l;
} else if (end - bp > 2 && in_string && bp[1] == '\\'
&& bp[2] == '"' && bp[3] == '>') {
&& bp[2] == '"' && bp[3] == endchar) {
bp += 2;
}
}
}
if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') {
bp += 3; // skip t_xx, xx may be '-' or '>'
bp += 3; // skip t_xx, xx may be '-' or '>'/'}'
} else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) {
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true);
if (l == 0) {
@ -688,7 +682,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const
}
}
if (bp <= end && *bp == '>') { // found matching '>'
if (bp <= end && *bp == endchar) { // found matching '>' or '}'
end_of_name = bp + 1;
// Which modifiers are given?
@ -724,11 +718,11 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const
} else {
l = utfc_ptr2len(last_dash + 1);
}
if (modifiers != 0 && last_dash[l + 1] == '>') {
if (modifiers != 0 && last_dash[l + 1] == endchar) {
key = utf_ptr2char(last_dash + off);
} else {
key = get_special_key_code(last_dash + off);
if (!keep_x_key) {
if (!(flags & FSK_KEEP_X_KEY)) {
key = handle_x_keys(key);
}
}
@ -741,7 +735,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const
// includes the modifier.
key = simplify_key(key, &modifiers);
if (!keycode) {
if (!(flags & FSK_KEYCODE)) {
// don't want keycode, use single byte code
if (key == K_BS) {
key = BS;
@ -753,7 +747,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const
// Normal Key with modifier:
// Try to make a single byte code (except for Alt/Meta modifiers).
if (!IS_SPECIAL(key)) {
key = extract_modifiers(key, &modifiers, simplify, did_simplify);
key = extract_modifiers(key, &modifiers, flags & FSK_SIMPLIFY, did_simplify);
}
*modp = modifiers;
@ -945,8 +939,9 @@ 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, true, false,
(flags & REPTERM_NO_SIMPLIFY) == 0, did_simplify);
slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen,
FSK_KEYCODE | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY),
did_simplify);
if (slen) {
dlen += slen;
continue;

View File

@ -507,6 +507,23 @@ enum key_extra {
? 0 \
: FLAG_CPO_BSLASH)
// Flags for replace_termcodes()
enum {
REPTERM_FROM_PART = 1,
REPTERM_DO_LT = 2,
REPTERM_NO_SPECIAL = 4,
REPTERM_NO_SIMPLIFY = 8,
};
// Flags for find_special_key()
enum {
FSK_KEYCODE = 0x01, ///< prefer key code, e.g. K_DEL in place of DEL
FSK_KEEP_X_KEY = 0x02, ///< dont translate xHome to Home key
FSK_IN_STRING = 0x04, ///< in string, double quote is escaped
FSK_SIMPLIFY = 0x08, ///< simplify <C-H>, etc.
FSK_CURLY = 0x10, ///< {C-x} instead of <C-x>
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "keymap.h.generated.h"
#endif

View File

@ -5222,7 +5222,8 @@ int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt)
} else if (has_lt) {
arg--; // put arg at the '<'
modifiers = 0;
key = find_special_key(&arg, len + 1, &modifiers, true, true, false, true, NULL);
key = find_special_key(&arg, len + 1, &modifiers,
FSK_KEYCODE | FSK_KEEP_X_KEY | FSK_SIMPLIFY, NULL);
if (modifiers) { // can't handle modifiers here
key = 0;
}

View File

@ -240,7 +240,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, true, false, false, NULL);
= trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, FSK_KEYCODE, NULL);
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);

View File

@ -76,7 +76,7 @@ func Test_backspace_ctrl_u()
set cpo-=<
inoremap <c-u> <left><c-u>
exe "normal Avim3\<C-U>\<Esc>\<CR>"
exe "normal Avim3\{C-U}\<Esc>\<CR>"
iunmap <c-u>
exe "normal Avim4\<C-U>\<C-U>\<Esc>\<CR>"
@ -86,7 +86,7 @@ func Test_backspace_ctrl_u()
exe "normal A vim6\<Esc>Azwei\<C-G>u\<C-U>\<Esc>\<CR>"
inoremap <c-u> <left><c-u>
exe "normal A vim7\<C-U>\<C-U>\<Esc>\<CR>"
exe "normal A vim7\{C-U}\{C-U}\<Esc>\<CR>"
call assert_equal([
\ "1 this shouldn't be deleted",

View File

@ -62,7 +62,7 @@ func Test_map_ctrl_c_insert()
inoremap <c-c> <ctrl-c>
cnoremap <c-c> dummy
cunmap <c-c>
call feedkeys("GoTEST2: CTRL-C |\<C-C>A|\<Esc>", "xt")
call feedkeys("GoTEST2: CTRL-C |\{C-C}A|\<Esc>", "xt")
call assert_equal('TEST2: CTRL-C |<ctrl-c>A|', getline('$'))
unmap! <c-c>
set nomodified
@ -71,7 +71,7 @@ endfunc
func Test_map_ctrl_c_visual()
" mapping of ctrl-c in Visual mode
vnoremap <c-c> :<C-u>$put ='vmap works'
call feedkeys("GV\<C-C>\<CR>", "xt")
call feedkeys("GV\{C-C}\<CR>", "xt")
call assert_equal('vmap works', getline('$'))
vunmap <c-c>
set nomodified
@ -221,7 +221,7 @@ endfunc
func Test_map_meta_quotes()
imap <M-"> foo
call feedkeys("Go-\<M-\">-\<Esc>", "xt")
call feedkeys("Go-\{M-\"}-\<Esc>", "xt")
call assert_equal("-foo-", getline('$'))
set nomodified
iunmap <M-">

View File

@ -115,7 +115,7 @@ endfunc
func Test_mapping_at_hit_return_prompt()
nnoremap <C-B> :echo "hit ctrl-b"<CR>
call feedkeys(":ls\<CR>", "xt")
call feedkeys("\<C-B>", "xt")
call feedkeys("\{C-B}", "xt")
call assert_match('hit ctrl-b', Screenline(&lines - 1))
nunmap <C-B>
endfunc

View File

@ -318,10 +318,4 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext()
#define REPLACE_CR_NCHAR (-1)
#define REPLACE_NL_NCHAR (-2)
// Flags for replace_termcodes()
#define REPTERM_FROM_PART 1
#define REPTERM_DO_LT 2
#define REPTERM_NO_SPECIAL 4
#define REPTERM_NO_SIMPLIFY 8
#endif // NVIM_VIM_H

View File

@ -1815,10 +1815,18 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no
*v_p++ = (char)ch;
break;
}
// Special key, e.g.: "\<C-W>"
case '<': {
// Special key, e.g.: "\<C-W>" or "\{C-W}"
case '<':
case '{': {
int flags = FSK_KEYCODE | FSK_IN_STRING;
if (*p == '<') {
flags |= FSK_SIMPLIFY;
} else {
flags |= FSK_CURLY;
}
const size_t special_len = trans_special((const char_u **)&p, (size_t)(e - p),
(char_u *)v_p, true, true, true, NULL);
(char_u *)v_p, flags, NULL);
if (special_len != 0) {
v_p += special_len;
} else {

View File

@ -5,7 +5,7 @@ local ffi = helpers.ffi
local eq = helpers.eq
local neq = helpers.neq
local keymap = helpers.cimport("./src/nvim/keymap.h")
local keymap = helpers.cimport('./src/nvim/keymap.h')
local NULL = helpers.NULL
describe('keymap.c', function()
@ -16,12 +16,12 @@ describe('keymap.c', function()
itp('no keycode', function()
srcp[0] = 'abc'
eq(0, keymap.find_special_key(srcp, 3, modp, false, false, false, false, NULL))
eq(0, keymap.find_special_key(srcp, 3, modp, 0, NULL))
end)
itp('keycode with multiple modifiers', function()
srcp[0] = '<C-M-S-A>'
neq(0, keymap.find_special_key(srcp, 9, modp, false, false, false, false, NULL))
neq(0, keymap.find_special_key(srcp, 9, modp, 0, NULL))
neq(0, modp[0])
end)
@ -29,22 +29,22 @@ describe('keymap.c', function()
-- Compare other capitalizations to this.
srcp[0] = '<C-A>'
local all_caps_key =
keymap.find_special_key(srcp, 5, modp, false, false, false, false, NULL)
keymap.find_special_key(srcp, 5, modp, 0, NULL)
local all_caps_mod = modp[0]
srcp[0] = '<C-a>'
eq(all_caps_key,
keymap.find_special_key(srcp, 5, modp, false, false, false, false, NULL))
keymap.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
srcp[0] = '<c-A>'
eq(all_caps_key,
keymap.find_special_key(srcp, 5, modp, false, false, false, false, NULL))
keymap.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
srcp[0] = '<c-a>'
eq(all_caps_key,
keymap.find_special_key(srcp, 5, modp, false, false, false, false, NULL))
keymap.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
end)
@ -52,20 +52,20 @@ describe('keymap.c', function()
-- Unescaped with in_string=false
srcp[0] = '<C-">'
eq(string.byte('"'),
keymap.find_special_key(srcp, 5, modp, false, false, false, false, NULL))
keymap.find_special_key(srcp, 5, modp, 0, NULL))
-- Unescaped with in_string=true
eq(0, keymap.find_special_key(srcp, 5, modp, false, false, true, false, NULL))
eq(0, keymap.find_special_key(srcp, 5, modp, keymap.FSK_IN_STRING, NULL))
-- Escaped with in_string=false
srcp[0] = '<C-\\">'
-- Should fail because the key is invalid
-- (more than 1 non-modifier character).
eq(0, keymap.find_special_key(srcp, 6, modp, false, false, false, false, NULL))
eq(0, keymap.find_special_key(srcp, 6, modp, 0, NULL))
-- Escaped with in_string=true
eq(string.byte('"'),
keymap.find_special_key(srcp, 6, modp, false, false, true, false, NULL))
keymap.find_special_key(srcp, 6, modp, keymap.FSK_IN_STRING, NULL))
end)
end)