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-\">". 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 Don't use <Char-xxxx> to get a UTF-8 character, use \uxxxx as
mentioned above. 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 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. 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; ++name;
break; break;
// Special key, e.g.: "\<C-W>" // Special key, e.g.: "\<C-W>" or "\{C-W}"
case '<': 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) { if (extra != 0) {
name += extra; name += extra;
if (name >= rettv->vval.v_string + len) { 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; break;
} }
}
FALLTHROUGH; FALLTHROUGH;
default: 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[in] src_len Length of the srcp.
/// @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] keycode Prefer key code, e.g. K_DEL in place of DEL. /// @param[in] flags FSK_ values
/// @param[in] in_string Inside a double quoted string
/// @param[in] simplify simplify <C-H>, etc.
/// @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 bool keycode, const bool in_string, const bool simplify, const int flags, bool *const did_simplify)
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;
int key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string, simplify, int key = find_special_key(srcp, src_len, &modifiers, flags, did_simplify);
did_simplify);
if (key == 0) { if (key == 0) {
return 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 /// 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,out] srcp Translated <> name. Is advanced to after the <> name.
/// @param[in] src_len srcp length. /// @param[in] src_len srcp length.
/// @param[out] modp Location where information about modifiers is saved. /// @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] flags FSK_ values
/// @param[in] keep_x_key Dont translate xHome to Home key. /// @param[out] did_simplify FSK_SIMPLIFY and found <C-H>, etc.
/// @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.
/// ///
/// @return Key and modifiers or 0 if there is no match. /// @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, 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 int flags, bool *const did_simplify)
const bool simplify, bool *const did_simplify)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3)
{ {
const char_u *last_dash; 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 *src;
const char_u *bp; const char_u *bp;
const char_u *const end = *srcp + src_len - 1; const char_u *const end = *srcp + src_len - 1;
const bool in_string = flags & FSK_IN_STRING;
int modifiers; int modifiers;
int bit; int bit;
int key; int key;
const int endchar = (flags & FSK_CURLY) ? '}' : '>';
uvarnumber_T n; uvarnumber_T n;
int l; int l;
@@ -653,7 +647,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const
} }
src = *srcp; src = *srcp;
if (src[0] != '<') { if (src[0] != ((flags & FSK_CURLY) ? '{' : '<')) {
return 0; 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-?>. // Anything accepted, like <C-?>.
// <C-"> or <M-"> are not special in strings as " is // <C-"> or <M-"> are not special in strings as " is
// the string delimiter. With a backslash it works: <M-\"> // 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; bp += l;
} else if (end - bp > 2 && in_string && bp[1] == '\\' } else if (end - bp > 2 && in_string && bp[1] == '\\'
&& bp[2] == '"' && bp[3] == '>') { && bp[2] == '"' && bp[3] == endchar) {
bp += 2; bp += 2;
} }
} }
} }
if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') { 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) { } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) {
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true); vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true);
if (l == 0) { 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; end_of_name = bp + 1;
// Which modifiers are given? // 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 { } else {
l = utfc_ptr2len(last_dash + 1); 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); key = utf_ptr2char(last_dash + off);
} else { } else {
key = get_special_key_code(last_dash + off); key = get_special_key_code(last_dash + off);
if (!keep_x_key) { if (!(flags & FSK_KEEP_X_KEY)) {
key = handle_x_keys(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. // includes the modifier.
key = simplify_key(key, &modifiers); key = simplify_key(key, &modifiers);
if (!keycode) { if (!(flags & FSK_KEYCODE)) {
// don't want keycode, use single byte code // don't want keycode, use single byte code
if (key == K_BS) { if (key == K_BS) {
key = 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: // Normal Key with modifier:
// Try to make a single byte code (except for Alt/Meta modifiers). // Try to make a single byte code (except for Alt/Meta modifiers).
if (!IS_SPECIAL(key)) { if (!IS_SPECIAL(key)) {
key = extract_modifiers(key, &modifiers, simplify, did_simplify); key = extract_modifiers(key, &modifiers, flags & FSK_SIMPLIFY, did_simplify);
} }
*modp = modifiers; *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, slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen,
(flags & REPTERM_NO_SIMPLIFY) == 0, did_simplify); FSK_KEYCODE | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY),
did_simplify);
if (slen) { if (slen) {
dlen += slen; dlen += slen;
continue; continue;

View File

@@ -507,6 +507,23 @@ enum key_extra {
? 0 \ ? 0 \
: FLAG_CPO_BSLASH) : 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 #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "keymap.h.generated.h" # include "keymap.h.generated.h"
#endif #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) { } else if (has_lt) {
arg--; // put arg at the '<' arg--; // put arg at the '<'
modifiers = 0; 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 if (modifiers) { // can't handle modifiers here
key = 0; key = 0;
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -318,10 +318,4 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext()
#define REPLACE_CR_NCHAR (-1) #define REPLACE_CR_NCHAR (-1)
#define REPLACE_NL_NCHAR (-2) #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 #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; *v_p++ = (char)ch;
break; break;
} }
// Special key, e.g.: "\<C-W>" // Special key, e.g.: "\<C-W>" or "\{C-W}"
case '<': { 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), 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) { if (special_len != 0) {
v_p += special_len; v_p += special_len;
} else { } else {

View File

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