aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-03-31 15:47:53 +0800
committerzeertzjq <zeertzjq@outlook.com>2022-04-29 15:51:03 +0800
commitdde4f09f51ffaf8df5cc2a81eed935e31e1f94ba (patch)
tree392ec276e38a6a980d5610060795eea730b73311
parent188537efb32d02081c1821cb5b48fbcf59230732 (diff)
downloadrneovim-dde4f09f51ffaf8df5cc2a81eed935e31e1f94ba.tar.gz
rneovim-dde4f09f51ffaf8df5cc2a81eed935e31e1f94ba.tar.bz2
rneovim-dde4f09f51ffaf8df5cc2a81eed935e31e1f94ba.zip
vim-patch:8.1.2145: cannot map <C-H> when modifyOtherKeys is enabled
Problem: Cannot map <C-H> when modifyOtherKeys is enabled. Solution: Add the <C-H> mapping twice, both with modifier and as 0x08. Use only the first one when modifyOtherKeys has been detected. https://github.com/vim/vim/commit/459fd785e4a8d044147a3f83a5fca8748528aa84 Add REPTERM_NO_SPECIAL instead of REPTERM_SPECIAL because the meaning of "special" is different between Vim and Nvim. Omit seenModifyOtherKeys as Nvim supports attaching multiple UIs. Omit tests as they send terminal codes. Keep the behavior of API functions.
-rw-r--r--src/nvim/api/private/helpers.c5
-rw-r--r--src/nvim/api/vim.c14
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/eval.c2
-rw-r--r--src/nvim/eval/funcs.c2
-rw-r--r--src/nvim/ex_docmd.c3
-rw-r--r--src/nvim/getchar.c549
-rw-r--r--src/nvim/getchar.h6
-rw-r--r--src/nvim/keymap.c111
-rw-r--r--src/nvim/menu.c4
-rw-r--r--src/nvim/option.c4
-rw-r--r--src/nvim/os/input.c3
-rw-r--r--src/nvim/vim.h6
-rw-r--r--src/nvim/viml/parser/expressions.c5
-rw-r--r--test/functional/api/keymap_spec.lua2
-rw-r--r--test/unit/keymap_spec.lua21
16 files changed, 402 insertions, 337 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 5ba4700f62..8383f29400 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -632,7 +632,7 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod
} else {
parsed_args.desc = NULL;
}
- if (parsed_args.lhs_len > MAXMAPLEN) {
+ if (parsed_args.lhs_len > MAXMAPLEN || parsed_args.alt_lhs_len > MAXMAPLEN) {
api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data);
goto fail_and_free;
}
@@ -1128,6 +1128,9 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua)
for (const mapblock_T *current_maphash = get_maphash(i, buf);
current_maphash;
current_maphash = current_maphash->m_next) {
+ if (current_maphash->m_simplified) {
+ continue;
+ }
// Check for correct mode
if (int_mode & current_maphash->m_mode) {
mapblock_fill_dict(dict, current_maphash, buffer_value, false);
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 0f9a4a0e0d..2174cd1620 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -403,9 +403,19 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, Bool
return (String) { .data = NULL, .size = 0 };
}
+ int flags = 0;
+ if (from_part) {
+ flags |= REPTERM_FROM_PART;
+ }
+ if (do_lt) {
+ flags |= REPTERM_DO_LT;
+ }
+ if (!special) {
+ flags |= REPTERM_NO_SPECIAL;
+ }
+
char *ptr = NULL;
- replace_termcodes((char_u *)str.data, str.size, (char_u **)&ptr,
- from_part, do_lt, special, CPO_TO_CPO_FLAGS);
+ replace_termcodes((char_u *)str.data, str.size, (char_u **)&ptr, flags, NULL, CPO_TO_CPO_FLAGS);
return cstr_as_string(ptr);
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 8d2f7c4545..c71d022018 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -356,6 +356,8 @@ struct mapblock {
LuaRef m_luaref; // lua function reference as rhs
int m_keylen; // strlen(m_keys)
int m_mode; // valid mode
+ int m_simplified; // m_keys was simplified, do no use this map
+ // if keys are typed
int m_noremap; // if non-zero no re-mapping for m_str
char m_silent; // <silent> used, don't echo commands
char m_nowait; // <nowait> used
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index e192a6de6b..af6e7e470d 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -4965,7 +4965,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
// Special key, e.g.: "\<C-W>"
case '<':
- extra = trans_special((const char_u **)&p, STRLEN(p), name, true, true);
+ extra = trans_special((const char_u **)&p, STRLEN(p), name, true, true, true, NULL);
if (extra != 0) {
name += extra;
if (name >= rettv->vval.v_string + len) {
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index f97ceedeb7..71a090afed 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -5684,7 +5684,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
mode = get_map_mode((char_u **)&which, 0);
- keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, true,
+ keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, REPTERM_FROM_PART | REPTERM_DO_LT, NULL,
CPO_TO_CPO_FLAGS);
rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
xfree(keys_buf);
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 4562f6c751..f3b11cc103 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5180,8 +5180,7 @@ int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, lo
char_u *rep_buf = NULL;
garray_T *gap;
- replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, true,
- CPO_TO_CPO_FLAGS);
+ replace_termcodes(rep, STRLEN(rep), &rep_buf, 0, NULL, CPO_TO_CPO_FLAGS);
if (rep_buf == NULL) {
// Can't replace termcodes - try using the string as is
rep_buf = vim_strsave(rep);
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index f2df7b49fd..89a9a1ea95 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -2711,11 +2711,12 @@ int fix_input_buffer(char_u *buf, int len)
/// @param[in] orig_rhs_len `strlen` of orig_rhs.
/// @param[in] cpo_flags See param docs for @ref replace_termcodes.
/// @param[out] mapargs MapArguments struct holding the replaced strings.
-void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const char_u *orig_rhs,
- const size_t orig_rhs_len, LuaRef rhs_lua, int cpo_flags,
- MapArguments *mapargs)
+void set_maparg_lhs_rhs(const char_u *const orig_lhs, const size_t orig_lhs_len,
+ const char_u *const orig_rhs, const size_t orig_rhs_len,
+ const LuaRef rhs_lua, const int cpo_flags, MapArguments *const mapargs)
{
char_u *lhs_buf = NULL;
+ char_u *alt_lhs_buf = NULL;
char_u *rhs_buf = NULL;
// If mapping has been given as ^V<C_UP> say, then replace the term codes
@@ -2725,10 +2726,22 @@ void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const
// replace_termcodes() may move the result to allocated memory, which
// needs to be freed later (*lhs_buf and *rhs_buf).
// replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
- char_u *replaced = replace_termcodes(orig_lhs, orig_lhs_len, &lhs_buf,
- true, true, true, cpo_flags);
+ // If something like <C-H> is simplified to 0x08 then mark it as simplified.
+ bool did_simplify = false;
+ const int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
+ char_u *replaced = replace_termcodes(orig_lhs, orig_lhs_len, &lhs_buf, flags, &did_simplify,
+ cpo_flags);
mapargs->lhs_len = STRLEN(replaced);
STRLCPY(mapargs->lhs, replaced, sizeof(mapargs->lhs));
+ if (did_simplify) {
+ replaced = replace_termcodes(orig_lhs, orig_lhs_len, &alt_lhs_buf, flags | REPTERM_NO_SIMPLIFY,
+ NULL, cpo_flags);
+ mapargs->alt_lhs_len = STRLEN(replaced);
+ STRLCPY(mapargs->alt_lhs, replaced, sizeof(mapargs->alt_lhs));
+ } else {
+ mapargs->alt_lhs_len = 0;
+ }
+
mapargs->rhs_lua = rhs_lua;
if (rhs_lua == LUA_NOREF) {
@@ -2741,8 +2754,8 @@ void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const
mapargs->rhs_len = 0;
mapargs->rhs_is_noop = true;
} else {
- replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf,
- false, true, true, cpo_flags);
+ replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, REPTERM_DO_LT, NULL,
+ cpo_flags);
mapargs->rhs_len = STRLEN(replaced);
mapargs->rhs_is_noop = false;
mapargs->rhs = xcalloc(mapargs->rhs_len + 1, sizeof(char_u));
@@ -2760,6 +2773,7 @@ void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const
}
xfree(lhs_buf);
+ xfree(alt_lhs_buf);
xfree(rhs_buf);
}
@@ -2894,15 +2908,9 @@ int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *mapargs)
int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T *buf)
{
mapblock_T *mp, **mpp;
- char_u *p;
+ const char_u *p;
int n;
- int len = 0; // init for GCC
- int did_it = false;
- int did_local = false;
- int round;
int retval = 0;
- int hash;
- int new_hash;
mapblock_T **abbr_table;
mapblock_T **map_table;
int noremap;
@@ -2929,8 +2937,9 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
validate_maphash();
- bool has_lhs = (args->lhs[0] != NUL);
- bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop;
+ const bool has_lhs = (args->lhs[0] != NUL);
+ const bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop;
+ const bool do_print = !has_lhs || (maptype != 1 && !has_rhs);
// check for :unmap without argument
if (maptype == 1 && !has_lhs) {
@@ -2938,298 +2947,323 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
goto theend;
}
- char_u *lhs = (char_u *)&args->lhs;
- char_u *rhs = args->rhs;
- char_u *orig_rhs = args->orig_rhs;
+ const char_u *lhs = (char_u *)&args->lhs;
+ const char_u *const rhs = args->rhs;
+ const char_u *const orig_rhs = args->orig_rhs;
+ const bool did_simplify = args->alt_lhs_len != 0;
- // check arguments and translate function keys
- if (has_lhs) {
- len = (int)args->lhs_len;
- if (len > MAXMAPLEN) {
- retval = 1;
- goto theend;
- }
+ // The following is done twice if we have two versions of keys
+ for (int keyround = 1; keyround <= 2; keyround++) {
+ bool did_it = false;
+ bool did_local = false;
+ int len = (int)args->lhs_len;
- if (is_abbrev && maptype != 1) {
- //
- // If an abbreviation ends in a keyword character, the
- // rest must be all keyword-char or all non-keyword-char.
- // Otherwise we won't be able to find the start of it in a
- // vi-compatible way.
- //
- int same = -1;
-
- const int first = vim_iswordp(lhs);
- int last = first;
- p = lhs + utfc_ptr2len(lhs);
- n = 1;
- while (p < lhs + len) {
- n++; // nr of (multi-byte) chars
- last = vim_iswordp(p); // type of last char
- if (same == -1 && last != first) {
- same = n - 1; // count of same char type
- }
- p += utfc_ptr2len(p);
+ if (keyround == 2) {
+ if (!did_simplify) {
+ break;
}
- if (last && n > 2 && same >= 0 && same < n - 1) {
+ lhs = (char_u *)&args->alt_lhs;
+ len = (int)args->alt_lhs_len;
+ } else if (did_simplify && do_print) {
+ // when printing always use the not-simplified map
+ lhs = (char_u *)&args->alt_lhs;
+ len = (int)args->alt_lhs_len;
+ }
+
+ // check arguments and translate function keys
+ if (has_lhs) {
+ if (len > MAXMAPLEN) {
retval = 1;
goto theend;
}
- // An abbreviation cannot contain white space.
- for (n = 0; n < len; n++) {
- if (ascii_iswhite(lhs[n])) {
+
+ if (is_abbrev && maptype != 1) {
+ //
+ // If an abbreviation ends in a keyword character, the
+ // rest must be all keyword-char or all non-keyword-char.
+ // Otherwise we won't be able to find the start of it in a
+ // vi-compatible way.
+ //
+ int same = -1;
+
+ const int first = vim_iswordp(lhs);
+ int last = first;
+ p = lhs + utfc_ptr2len(lhs);
+ n = 1;
+ while (p < lhs + len) {
+ n++; // nr of (multi-byte) chars
+ last = vim_iswordp(p); // type of last char
+ if (same == -1 && last != first) {
+ same = n - 1; // count of same char type
+ }
+ p += utfc_ptr2len(p);
+ }
+ if (last && n > 2 && same >= 0 && same < n - 1) {
retval = 1;
goto theend;
}
- } // for
+ // An abbreviation cannot contain white space.
+ for (n = 0; n < len; n++) {
+ if (ascii_iswhite(lhs[n])) {
+ retval = 1;
+ goto theend;
+ }
+ } // for
+ }
}
- }
- if (has_lhs && has_rhs && is_abbrev) { // if we will add an abbreviation,
- no_abbr = false; // reset flag that indicates there are no abbreviations
- }
+ if (has_lhs && has_rhs && is_abbrev) { // if we will add an abbreviation,
+ no_abbr = false; // reset flag that indicates there are no abbreviations
+ }
- if (!has_lhs || (maptype != 1 && !has_rhs)) {
- msg_start();
- }
+ if (do_print) {
+ msg_start();
+ }
- // Check if a new local mapping wasn't already defined globally.
- if (map_table == buf->b_maphash && has_lhs && has_rhs && maptype != 1) {
- // need to loop over all global hash lists
- for (hash = 0; hash < 256 && !got_int; hash++) {
- if (is_abbrev) {
- if (hash != 0) { // there is only one abbreviation list
- break;
+ // Check if a new local mapping wasn't already defined globally.
+ if (map_table == buf->b_maphash && has_lhs && has_rhs && maptype != 1) {
+ // need to loop over all global hash lists
+ for (int hash = 0; hash < 256 && !got_int; hash++) {
+ if (is_abbrev) {
+ if (hash != 0) { // there is only one abbreviation list
+ break;
+ }
+ mp = first_abbr;
+ } else {
+ mp = maphash[hash];
}
- mp = first_abbr;
- } else {
- mp = maphash[hash];
- }
- for (; mp != NULL && !got_int; mp = mp->m_next) {
- // check entries with the same mode
- if ((mp->m_mode & mode) != 0
- && mp->m_keylen == len
- && args->unique
- && STRNCMP(mp->m_keys, lhs, (size_t)len) == 0) {
- if (is_abbrev) {
- semsg(_("E224: global abbreviation already exists for %s"),
- mp->m_keys);
- } else {
- semsg(_("E225: global mapping already exists for %s"), mp->m_keys);
+ for (; mp != NULL && !got_int; mp = mp->m_next) {
+ // check entries with the same mode
+ if ((mp->m_mode & mode) != 0
+ && mp->m_keylen == len
+ && args->unique
+ && STRNCMP(mp->m_keys, lhs, (size_t)len) == 0) {
+ if (is_abbrev) {
+ semsg(_("E224: global abbreviation already exists for %s"),
+ mp->m_keys);
+ } else {
+ semsg(_("E225: global mapping already exists for %s"), mp->m_keys);
+ }
+ retval = 5;
+ goto theend;
}
- retval = 5;
- goto theend;
}
}
}
- }
- // When listing global mappings, also list buffer-local ones here.
- if (map_table != buf->b_maphash && !has_rhs && maptype != 1) {
- // need to loop over all global hash lists
- for (hash = 0; hash < 256 && !got_int; hash++) {
- if (is_abbrev) {
- if (hash != 0) { // there is only one abbreviation list
- break;
+ // When listing global mappings, also list buffer-local ones here.
+ if (map_table != buf->b_maphash && !has_rhs && maptype != 1) {
+ // need to loop over all global hash lists
+ for (int hash = 0; hash < 256 && !got_int; hash++) {
+ if (is_abbrev) {
+ if (hash != 0) { // there is only one abbreviation list
+ break;
+ }
+ mp = buf->b_first_abbr;
+ } else {
+ mp = buf->b_maphash[hash];
}
- mp = buf->b_first_abbr;
- } else {
- mp = buf->b_maphash[hash];
- }
- for (; mp != NULL && !got_int; mp = mp->m_next) {
- // check entries with the same mode
- if ((mp->m_mode & mode) != 0) {
- if (!has_lhs) { // show all entries
- showmap(mp, true);
- did_local = true;
- } else {
- n = mp->m_keylen;
- if (STRNCMP(mp->m_keys, lhs, (size_t)(n < len ? n : len)) == 0) {
+ for (; mp != NULL && !got_int; mp = mp->m_next) {
+ // check entries with the same mode
+ if ((mp->m_mode & mode) != 0) {
+ if (!has_lhs) { // show all entries
showmap(mp, true);
did_local = true;
+ } else {
+ n = mp->m_keylen;
+ if (STRNCMP(mp->m_keys, lhs, (size_t)(n < len ? n : len)) == 0) {
+ showmap(mp, true);
+ did_local = true;
+ }
}
}
}
}
}
- }
- // Find an entry in the maphash[] list that matches.
- // For :unmap we may loop two times: once to try to unmap an entry with a
- // matching 'from' part, a second time, if the first fails, to unmap an
- // entry with a matching 'to' part. This was done to allow ":ab foo bar"
- // to be unmapped by typing ":unab foo", where "foo" will be replaced by
- // "bar" because of the abbreviation.
- for (round = 0; (round == 0 || maptype == 1) && round <= 1
- && !did_it && !got_int; round++) {
- // need to loop over all hash lists
- for (hash = 0; hash < 256 && !got_int; hash++) {
- if (is_abbrev) {
- if (hash > 0) { // there is only one abbreviation list
- break;
- }
- mpp = abbr_table;
- } else {
- mpp = &(map_table[hash]);
- }
- for (mp = *mpp; mp != NULL && !got_int; mp = *mpp) {
- if (!(mp->m_mode & mode)) { // skip entries with wrong mode
- mpp = &(mp->m_next);
- continue;
+ // Find an entry in the maphash[] list that matches.
+ // For :unmap we may loop two times: once to try to unmap an entry with a
+ // matching 'from' part, a second time, if the first fails, to unmap an
+ // entry with a matching 'to' part. This was done to allow ":ab foo bar"
+ // to be unmapped by typing ":unab foo", where "foo" will be replaced by
+ // "bar" because of the abbreviation.
+ for (int round = 0; (round == 0 || maptype == 1) && round <= 1
+ && !did_it && !got_int; round++) {
+ // need to loop over all hash lists
+ for (int hash = 0; hash < 256 && !got_int; hash++) {
+ if (is_abbrev) {
+ if (hash > 0) { // there is only one abbreviation list
+ break;
+ }
+ mpp = abbr_table;
+ } else {
+ mpp = &(map_table[hash]);
}
- if (!has_lhs) { // show all entries
- showmap(mp, map_table != maphash);
- did_it = true;
- } else { // do we have a match?
- if (round) { // second round: Try unmap "rhs" string
- n = (int)STRLEN(mp->m_str);
- p = mp->m_str;
- } else {
- n = mp->m_keylen;
- p = mp->m_keys;
+ for (mp = *mpp; mp != NULL && !got_int; mp = *mpp) {
+ if (!(mp->m_mode & mode)) { // skip entries with wrong mode
+ mpp = &(mp->m_next);
+ continue;
}
- if (STRNCMP(p, lhs, (size_t)(n < len ? n : len)) == 0) {
- if (maptype == 1) { // delete entry
- // Only accept a full match. For abbreviations we
- // ignore trailing space when matching with the
- // "lhs", since an abbreviation can't have
- // trailing space.
- if (n != len && (!is_abbrev || round || n > len
- || *skipwhite(lhs + n) != NUL)) {
+ if (!has_lhs) { // show all entries
+ showmap(mp, map_table != maphash);
+ did_it = true;
+ } else { // do we have a match?
+ if (round) { // second round: Try unmap "rhs" string
+ n = (int)STRLEN(mp->m_str);
+ p = mp->m_str;
+ } else {
+ n = mp->m_keylen;
+ p = mp->m_keys;
+ }
+ if (STRNCMP(p, lhs, (size_t)(n < len ? n : len)) == 0) {
+ if (maptype == 1) {
+ // Delete entry.
+ // Only accept a full match. For abbreviations
+ // we ignore trailing space when matching with
+ // the "lhs", since an abbreviation can't have
+ // trailing space.
+ if (n != len && (!is_abbrev || round || n > len
+ || *skipwhite(lhs + n) != NUL)) {
+ mpp = &(mp->m_next);
+ continue;
+ }
+ // We reset the indicated mode bits. If nothing
+ // is left the entry is deleted below.
+ mp->m_mode &= ~mode;
+ did_it = true; // remember we did something
+ } else if (!has_rhs) { // show matching entry
+ showmap(mp, map_table != maphash);
+ did_it = true;
+ } else if (n != len) { // new entry is ambiguous
mpp = &(mp->m_next);
continue;
- }
- // We reset the indicated mode bits. If nothing is
- // left the entry is deleted below.
- mp->m_mode &= ~mode;
- did_it = true; // remember we did something
- } else if (!has_rhs) { // show matching entry
- showmap(mp, map_table != maphash);
- did_it = true;
- } else if (n != len) { // new entry is ambiguous
- mpp = &(mp->m_next);
- continue;
- } else if (args->unique) {
- if (is_abbrev) {
- semsg(_("E226: abbreviation already exists for %s"), p);
+ } else if (args->unique) {
+ if (is_abbrev) {
+ semsg(_("E226: abbreviation already exists for %s"), p);
+ } else {
+ semsg(_("E227: mapping already exists for %s"), p);
+ }
+ retval = 5;
+ goto theend;
} else {
- semsg(_("E227: mapping already exists for %s"), p);
- }
- retval = 5;
- goto theend;
- } else { // new rhs for existing entry
- mp->m_mode &= ~mode; // remove mode bits
- if (mp->m_mode == 0 && !did_it) { // reuse entry
- XFREE_CLEAR(mp->m_str);
- XFREE_CLEAR(mp->m_orig_str);
- XFREE_CLEAR(mp->m_desc);
- NLUA_CLEAR_REF(mp->m_luaref);
-
- mp->m_str = vim_strsave(rhs);
- mp->m_orig_str = vim_strsave(orig_rhs);
- mp->m_luaref = args->rhs_lua;
- mp->m_noremap = noremap;
- mp->m_nowait = args->nowait;
- mp->m_silent = args->silent;
- mp->m_mode = mode;
- mp->m_expr = args->expr;
- mp->m_script_ctx = current_sctx;
- mp->m_script_ctx.sc_lnum += sourcing_lnum;
- nlua_set_sctx(&mp->m_script_ctx);
- if (args->desc != NULL) {
- mp->m_desc = xstrdup(args->desc);
+ // new rhs for existing entry
+ mp->m_mode &= ~mode; // remove mode bits
+ if (mp->m_mode == 0 && !did_it) { // reuse entry
+ XFREE_CLEAR(mp->m_str);
+ XFREE_CLEAR(mp->m_orig_str);
+ XFREE_CLEAR(mp->m_desc);
+ NLUA_CLEAR_REF(mp->m_luaref);
+
+ mp->m_str = vim_strsave(rhs);
+ mp->m_orig_str = vim_strsave(orig_rhs);
+ mp->m_luaref = args->rhs_lua;
+ mp->m_noremap = noremap;
+ mp->m_nowait = args->nowait;
+ mp->m_silent = args->silent;
+ mp->m_mode = mode;
+ mp->m_simplified = did_simplify && keyround == 1;
+ mp->m_expr = args->expr;
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ nlua_set_sctx(&mp->m_script_ctx);
+ if (args->desc != NULL) {
+ mp->m_desc = xstrdup(args->desc);
+ }
+ did_it = true;
}
- did_it = true;
}
- }
- if (mp->m_mode == 0) { // entry can be deleted
- mapblock_free(mpp);
- continue; // continue with *mpp
- }
+ if (mp->m_mode == 0) { // entry can be deleted
+ mapblock_free(mpp);
+ continue; // continue with *mpp
+ }
- // May need to put this entry into another hash list.
- new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
- if (!is_abbrev && new_hash != hash) {
- *mpp = mp->m_next;
- mp->m_next = map_table[new_hash];
- map_table[new_hash] = mp;
+ // May need to put this entry into another hash list.
+ int new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ if (!is_abbrev && new_hash != hash) {
+ *mpp = mp->m_next;
+ mp->m_next = map_table[new_hash];
+ map_table[new_hash] = mp;
- continue; // continue with *mpp
+ continue; // continue with *mpp
+ }
}
}
+ mpp = &(mp->m_next);
}
- mpp = &(mp->m_next);
}
}
- }
- if (maptype == 1) { // delete entry
- if (!did_it) {
- retval = 2; // no match
- } else if (*lhs == Ctrl_C) {
- // If CTRL-C has been unmapped, reuse it for Interrupting.
- if (map_table == buf->b_maphash) {
- buf->b_mapped_ctrl_c &= ~mode;
- } else {
- mapped_ctrl_c &= ~mode;
+ if (maptype == 1) {
+ // delete entry
+ if (!did_it) {
+ retval = 2; // no match
+ } else if (*lhs == Ctrl_C) {
+ // If CTRL-C has been unmapped, reuse it for Interrupting.
+ if (map_table == buf->b_maphash) {
+ buf->b_mapped_ctrl_c &= ~mode;
+ } else {
+ mapped_ctrl_c &= ~mode;
+ }
}
+ continue;
}
- goto theend;
- }
- if (!has_lhs || !has_rhs) { // print entries
- if (!did_it && !did_local) {
- if (is_abbrev) {
- msg(_("No abbreviation found"));
- } else {
- msg(_("No mapping found"));
+ if (!has_lhs || !has_rhs) {
+ // print entries
+ if (!did_it && !did_local) {
+ if (is_abbrev) {
+ msg(_("No abbreviation found"));
+ } else {
+ msg(_("No mapping found"));
+ }
}
+ goto theend; // listing finished
}
- goto theend; // listing finished
- }
- if (did_it) { // have added the new entry already
- goto theend;
- }
+ if (did_it) {
+ continue; // have added the new entry already
+ }
- // Get here when adding a new entry to the maphash[] list or abbrlist.
- mp = xmalloc(sizeof(mapblock_T));
+ // Get here when adding a new entry to the maphash[] list or abbrlist.
+ mp = xmalloc(sizeof(mapblock_T));
- // If CTRL-C has been mapped, don't always use it for Interrupting.
- if (*lhs == Ctrl_C) {
- if (map_table == buf->b_maphash) {
- buf->b_mapped_ctrl_c |= mode;
- } else {
- mapped_ctrl_c |= mode;
+ // If CTRL-C has been mapped, don't always use it for Interrupting.
+ if (*lhs == Ctrl_C) {
+ if (map_table == buf->b_maphash) {
+ buf->b_mapped_ctrl_c |= mode;
+ } else {
+ mapped_ctrl_c |= mode;
+ }
}
- }
- mp->m_keys = vim_strsave(lhs);
- mp->m_str = vim_strsave(rhs);
- mp->m_orig_str = vim_strsave(orig_rhs);
- mp->m_luaref = args->rhs_lua;
- mp->m_keylen = (int)STRLEN(mp->m_keys);
- mp->m_noremap = noremap;
- mp->m_nowait = args->nowait;
- mp->m_silent = args->silent;
- mp->m_mode = mode;
- mp->m_expr = args->expr;
- mp->m_script_ctx = current_sctx;
- mp->m_script_ctx.sc_lnum += sourcing_lnum;
- nlua_set_sctx(&mp->m_script_ctx);
- mp->m_desc = NULL;
- if (args->desc != NULL) {
- mp->m_desc = xstrdup(args->desc);
- }
-
- // add the new entry in front of the abbrlist or maphash[] list
- if (is_abbrev) {
- mp->m_next = *abbr_table;
- *abbr_table = mp;
- } else {
- n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
- mp->m_next = map_table[n];
- map_table[n] = mp;
+ mp->m_keys = vim_strsave(lhs);
+ mp->m_str = vim_strsave(rhs);
+ mp->m_orig_str = vim_strsave(orig_rhs);
+ mp->m_luaref = args->rhs_lua;
+ mp->m_keylen = (int)STRLEN(mp->m_keys);
+ mp->m_noremap = noremap;
+ mp->m_nowait = args->nowait;
+ mp->m_silent = args->silent;
+ mp->m_mode = mode;
+ mp->m_simplified = did_simplify && keyround == 1;
+ mp->m_expr = args->expr;
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ nlua_set_sctx(&mp->m_script_ctx);
+ mp->m_desc = NULL;
+ if (args->desc != NULL) {
+ mp->m_desc = xstrdup(args->desc);
+ }
+
+ // add the new entry in front of the abbrlist or maphash[] list
+ if (is_abbrev) {
+ mp->m_next = *abbr_table;
+ *abbr_table = mp;
+ } else {
+ n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ mp->m_next = map_table[n];
+ map_table[n] = mp;
+ }
}
theend:
@@ -3600,9 +3634,8 @@ bool map_to_exists(const char *const str, const char *const modechars, const boo
int retval;
char_u *buf;
- char_u *const rhs = replace_termcodes((const char_u *)str, strlen(str), &buf,
- false, true, true,
- CPO_TO_CPO_FLAGS);
+ const char_u *const rhs = replace_termcodes((const char_u *)str, strlen(str), &buf, REPTERM_DO_LT,
+ NULL, CPO_TO_CPO_FLAGS);
#define MAPMODE(mode, modechars, chr, modeflags) \
do { \
diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h
index 9b8605f1df..237f0632bd 100644
--- a/src/nvim/getchar.h
+++ b/src/nvim/getchar.h
@@ -48,6 +48,10 @@ struct map_arguments {
char_u lhs[MAXMAPLEN + 1];
size_t lhs_len;
+ /// Unsimplifed {lhs} of the mapping. If no simplification has been done then alt_lhs_len is 0.
+ char_u alt_lhs[MAXMAPLEN + 1];
+ size_t alt_lhs_len;
+
char_u *rhs; /// The {rhs} of the mapping.
size_t rhs_len;
LuaRef rhs_lua; /// lua function as rhs
@@ -59,7 +63,7 @@ struct map_arguments {
};
typedef struct map_arguments MapArguments;
#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, \
- { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL }
+ { 0 }, 0, { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL }
#define KEYLEN_PART_KEY (-1) // keylen value for incomplete key-code
#define KEYLEN_PART_MAP (-2) // keylen value for incomplete mapping
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 3fdc140ebd..07975545be 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -570,16 +570,18 @@ char_u *get_special_key_name(int c, int modifiers)
// 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[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 **srcp, const size_t src_len, char_u *const dst,
- const bool keycode, const bool in_string)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+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)
+ FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
int modifiers = 0;
- int key;
-
- key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string);
+ int key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string, simplify,
+ did_simplify);
if (key == 0) {
return 0;
}
@@ -626,11 +628,14 @@ unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst)
/// @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.
///
/// @return Key and modifiers or 0 if there is no match.
-int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, const bool keycode,
- const bool keep_x_key, const bool in_string)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+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)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3)
{
const char_u *last_dash;
const char_u *end_of_name;
@@ -748,7 +753,7 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
// 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);
+ key = extract_modifiers(key, &modifiers, simplify, did_simplify);
}
*modp = modifiers;
@@ -762,7 +767,10 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
/// Try to include modifiers (except alt/meta) in the key.
/// Changes "Shift-a" to 'A', "Ctrl-@" to <Nul>, etc.
-static int extract_modifiers(int key, int *modp)
+/// @param[in] simplify if false, don't do Ctrl
+/// @param[out] did_simplify set when it is not NULL and "simplify" is true and
+/// Ctrl is removed from modifiers
+static int extract_modifiers(int key, int *modp, const bool simplify, bool *const did_simplify)
{
int modifiers = *modp;
@@ -773,15 +781,19 @@ static int extract_modifiers(int key, int *modp)
modifiers &= ~MOD_MASK_SHIFT;
}
}
- if ((modifiers & MOD_MASK_CTRL) && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) {
+ // <C-H> and <C-h> mean the same thing, always use "H"
+ if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key)) {
key = TOUPPER_ASC(key);
- int new_key = CTRL_CHR(key);
- if (new_key != TAB && new_key != CAR && new_key != ESC) {
- key = new_key;
- modifiers &= ~MOD_MASK_CTRL;
- if (key == 0) { // <C-@> is <Nul>
- key = K_ZERO;
- }
+ }
+ if (simplify && (modifiers & MOD_MASK_CTRL)
+ && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) {
+ key = CTRL_CHR(key);
+ modifiers &= ~MOD_MASK_CTRL;
+ if (key == 0) { // <C-@> is <Nul>
+ key = K_ZERO;
+ }
+ if (did_simplify != NULL) {
+ *did_simplify = true;
}
}
@@ -853,34 +865,31 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag)
return 0; // Shouldn't get here
}
-/// Replace any terminal code strings with the equivalent internal
-/// representation
+/// Replace any terminal code strings with the equivalent internal representation.
+///
+/// Used for the "from" and "to" part of a mapping, and the "to" part of a menu command.
+/// Any strings like "<C-UP>" are also replaced, unless `special` is false.
+/// K_SPECIAL by itself is replaced by K_SPECIAL KS_SPECIAL KE_FILLER.
///
-/// Used for the "from" and "to" part of a mapping, and the "to" part of
-/// a menu command. Any strings like "<C-UP>" are also replaced, unless
-/// `special` is false. K_SPECIAL by itself is replaced by K_SPECIAL
-/// KS_SPECIAL KE_FILLER.
+/// When "flags" has REPTERM_FROM_PART, trailing <C-v> is included, otherwise it is removed (to make
+/// ":map xx ^V" map xx to nothing). When cpo_flags contains FLAG_CPO_BSLASH, a backslash can be
+/// used in place of <C-v>. All other <C-v> characters are removed.
///
/// @param[in] from What characters to replace.
/// @param[in] from_len Length of the "from" argument.
-/// @param[out] bufp Location where results were saved in case of success
-/// (allocated). Will be set to NULL in case of failure.
-/// @param[in] do_lt If true, also translate <lt>.
-/// @param[in] from_part If true, trailing <C-v> is included, otherwise it is
-/// removed (to make ":map xx ^V" map xx to nothing).
-/// When cpo_flags contains #FLAG_CPO_BSLASH, a backslash
-/// can be used in place of <C-v>. All other <C-v>
-/// characters are removed.
-/// @param[in] special Replace keycodes, e.g. <CR> becomes a "\n" char.
-/// @param[in] cpo_flags Relevant flags derived from p_cpo, see
-/// #CPO_TO_CPO_FLAGS.
+/// @param[out] bufp Location where results were saved in case of success (allocated).
+/// Will be set to NULL in case of failure.
+/// @param[in] flags REPTERM_FROM_PART see above
+/// REPTERM_DO_LT also translate <lt>
+/// REPTERM_NO_SPECIAL do not accept <key> notation
+/// REPTERM_NO_SIMPLIFY do not simplify <C-H> into 0x08, etc.
+/// @param[out] did_simplify set when some <C-H> code was simplied, unless it is NULL.
+/// @param[in] cpo_flags Relevant flags derived from p_cpo, see CPO_TO_CPO_FLAGS.
///
-/// @return Pointer to an allocated memory in case of success, "from" in case of
-/// failure. In case of success returned pointer is also saved to
-/// "bufp".
-char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bufp,
- const bool from_part, const bool do_lt, const bool special, int cpo_flags)
- FUNC_ATTR_NONNULL_ALL
+/// @return Pointer to an allocated memory, which is also saved to "bufp".
+char_u *replace_termcodes(const char_u *const from, const size_t from_len, char_u **const bufp,
+ const int flags, bool *const did_simplify, const int cpo_flags)
+ FUNC_ATTR_NONNULL_ARG(1, 3)
{
ssize_t i;
size_t slen;
@@ -888,10 +897,10 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu
size_t dlen = 0;
const char_u *src;
const char_u *const end = from + from_len - 1;
- int do_backslash; // backslash is a special character
char_u *result; // buffer for resulting string
- do_backslash = !(cpo_flags&FLAG_CPO_BSLASH);
+ const bool do_backslash = !(cpo_flags & FLAG_CPO_BSLASH); // backslash is a special character
+ const bool do_special = !(flags & REPTERM_NO_SPECIAL);
// Allocate space for the translation. Worst case a single character is
// replaced by 6 bytes (shifted special key), plus a NUL at the end.
@@ -901,7 +910,7 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu
src = from;
// Check for #n at start only: function key n
- if (from_part && from_len > 1 && src[0] == '#'
+ if ((flags & REPTERM_FROM_PART) && from_len > 1 && src[0] == '#'
&& ascii_isdigit(src[1])) { // function key
result[dlen++] = K_SPECIAL;
result[dlen++] = 'k';
@@ -916,8 +925,8 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu
// Copy each byte from *from to result[dlen]
while (src <= end) {
// Check for special <> keycodes, like "<C-S-LeftMouse>"
- if (special && (do_lt || ((end - src) >= 3
- && STRNCMP(src, "<lt>", 4) != 0))) {
+ if (do_special && ((flags & REPTERM_DO_LT) || ((end - src) >= 3
+ && STRNCMP(src, "<lt>", 4) != 0))) {
// Replace <SID> by K_SNR <script-nr> _.
// (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
if (end - src >= 4 && STRNICMP(src, "<SID>", 5) == 0) {
@@ -936,15 +945,15 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu
}
}
- slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, true,
- false);
+ slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, true, false,
+ (flags & REPTERM_NO_SIMPLIFY) == 0, did_simplify);
if (slen) {
dlen += slen;
continue;
}
}
- if (special) {
+ if (do_special) {
char_u *p, *s, len;
// Replace <Leader> by the value of "mapleader".
@@ -984,7 +993,7 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu
if (key == Ctrl_V || (do_backslash && key == '\\')) {
src++; // skip CTRL-V or backslash
if (src > end) {
- if (from_part) {
+ if (flags & REPTERM_FROM_PART) {
result[dlen++] = key;
}
break;
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index f648a06284..d2293a6923 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -236,8 +236,8 @@ void ex_menu(exarg_T *eap)
} else if (modes & MENU_TIP_MODE) {
map_buf = NULL; // Menu tips are plain text.
} else {
- map_to = (char *)replace_termcodes((char_u *)map_to, STRLEN(map_to),
- (char_u **)&map_buf, false, true, true, CPO_TO_CPO_FLAGS);
+ map_to = (char *)replace_termcodes((char_u *)map_to, STRLEN(map_to), (char_u **)&map_buf,
+ REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS);
}
menuarg.modes = modes;
menuarg.noremap[0] = noremap;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 49c76d2452..79231385ad 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -3015,7 +3015,7 @@ ambw_end:
} else if (varp == &p_pt) {
// 'pastetoggle': translate key codes like in a mapping
if (*p_pt) {
- (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, true,
+ (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, REPTERM_FROM_PART | REPTERM_DO_LT, NULL,
CPO_TO_CPO_FLAGS);
if (p != NULL) {
if (new_value_alloced) {
@@ -5222,7 +5222,7 @@ 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);
+ key = find_special_key(&arg, len + 1, &modifiers, true, true, false, true, NULL);
if (modifiers) { // can't handle modifiers here
key = 0;
}
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 745b888b5e..4c617c9031 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -239,8 +239,7 @@ size_t input_enqueue(String keys)
// K_SPECIAL(0x80).
uint8_t buf[19] = { 0 };
unsigned int new_size
- = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true,
- false);
+ = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true, false, true, NULL);
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 3c8a865fb1..2672d0b2bc 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -318,4 +318,10 @@ 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
index b8b0a38f44..ec747d56d4 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -1817,9 +1817,8 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no
}
// Special key, e.g.: "\<C-W>"
case '<': {
- const size_t special_len = (
- trans_special((const char_u **)&p, (size_t)(e - p),
- (char_u *)v_p, true, true));
+ const size_t special_len = trans_special((const char_u **)&p, (size_t)(e - p),
+ (char_u *)v_p, true, true, true, NULL);
if (special_len != 0) {
v_p += special_len;
} else {
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index c0edcde476..a11b5306f4 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -582,7 +582,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
it('can set mappings containing literal keycodes', function()
meths.set_keymap('n', '\n\r\n', 'rhs', {})
local expected = generate_mapargs('n', '<NL><CR><NL>', 'rhs')
- eq(expected, get_mapargs('n', '<C-j><CR><C-j>'))
+ eq(expected, get_mapargs('n', '<NL><CR><NL>'))
end)
it('can set mappings whose RHS is a <Nop>', function()
diff --git a/test/unit/keymap_spec.lua b/test/unit/keymap_spec.lua
index 595a19eb17..1255774f11 100644
--- a/test/unit/keymap_spec.lua
+++ b/test/unit/keymap_spec.lua
@@ -6,6 +6,7 @@ local eq = helpers.eq
local neq = helpers.neq
local keymap = helpers.cimport("./src/nvim/keymap.h")
+local NULL = helpers.NULL
describe('keymap.c', function()
@@ -15,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))
+ eq(0, keymap.find_special_key(srcp, 3, modp, false, false, false, false, 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))
+ neq(0, keymap.find_special_key(srcp, 9, modp, false, false, false, false, NULL))
neq(0, modp[0])
end)
@@ -28,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)
+ keymap.find_special_key(srcp, 5, modp, false, false, false, false, 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))
+ keymap.find_special_key(srcp, 5, modp, false, false, false, false, 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))
+ keymap.find_special_key(srcp, 5, modp, false, false, false, false, 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))
+ keymap.find_special_key(srcp, 5, modp, false, false, false, false, NULL))
eq(all_caps_mod, modp[0])
end)
@@ -51,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))
+ keymap.find_special_key(srcp, 5, modp, false, false, false, false, NULL))
-- Unescaped with in_string=true
- eq(0, keymap.find_special_key(srcp, 5, modp, false, false, true))
+ eq(0, keymap.find_special_key(srcp, 5, modp, false, false, true, false, 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))
+ eq(0, keymap.find_special_key(srcp, 6, modp, false, false, false, false, NULL))
-- Escaped with in_string=true
eq(string.byte('"'),
- keymap.find_special_key(srcp, 6, modp, false, false, true))
+ keymap.find_special_key(srcp, 6, modp, false, false, true, false, NULL))
end)
end)