commit abe91e1efec84c47c03a69ab8a998bb16f628084
parent 6832b626ea1b3413c445dfc23f4d921335dfeaf3
Author: zeertzjq <zeertzjq@outlook.com>
Date: Tue, 26 Apr 2022 15:05:56 +0800
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.
https://github.com/vim/vim/commit/ebe9d34aa07037cff2188a8dd424ee1f59cbb0bf
Change macros to enums to use them in unit tests.
Diffstat:
12 files changed, 83 insertions(+), 56 deletions(-)
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
@@ -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.
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
@@ -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:
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
@@ -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 Don’t 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;
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
@@ -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, ///< don’t 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
diff --git a/src/nvim/option.c b/src/nvim/option.c
@@ -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;
}
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
@@ -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);
diff --git a/src/nvim/testdir/test_backspace_opt.vim b/src/nvim/testdir/test_backspace_opt.vim
@@ -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",
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
@@ -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-">
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
@@ -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
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
@@ -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
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
@@ -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 {
diff --git a/test/unit/keymap_spec.lua b/test/unit/keymap_spec.lua
@@ -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)