summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-10-13 16:43:39 +0200
committerBram Moolenaar <Bram@vim.org>2019-10-13 16:43:39 +0200
commit459fd785e4a8d044147a3f83a5fca8748528aa84 (patch)
tree52c679e08a445bac0f650bff4d8118d6eb190d7b
parent171a921b51101c1261040d28a8147c8829b675d3 (diff)
downloadvim-git-459fd785e4a8d044147a3f83a5fca8748528aa84.tar.gz
patch 8.1.2145: cannot map <C-H> when modifyOtherKeys is enabledv8.1.2145
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.
-rw-r--r--src/eval.c3
-rw-r--r--src/getchar.c5
-rw-r--r--src/globals.h4
-rw-r--r--src/gui_mac.c6
-rw-r--r--src/gui_w32.c2
-rw-r--r--src/highlight.c3
-rw-r--r--src/if_ole.cpp2
-rw-r--r--src/main.c2
-rw-r--r--src/map.c616
-rw-r--r--src/menu.c3
-rw-r--r--src/misc2.c57
-rw-r--r--src/option.c2
-rw-r--r--src/proto/misc2.pro6
-rw-r--r--src/proto/term.pro2
-rw-r--r--src/structs.h2
-rw-r--r--src/term.c45
-rw-r--r--src/terminal.c10
-rw-r--r--src/testdir/test_termcodes.vim92
-rw-r--r--src/usercmd.c2
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h6
21 files changed, 535 insertions, 337 deletions
diff --git a/src/eval.c b/src/eval.c
index 0fe8fd34a..ace1e013f 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3526,7 +3526,8 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
break;
/* Special key, e.g.: "\<C-W>" */
- case '<': extra = trans_special(&p, name, TRUE, TRUE);
+ case '<': extra = trans_special(&p, name, TRUE, TRUE,
+ TRUE, NULL);
if (extra != 0)
{
name += extra;
diff --git a/src/getchar.c b/src/getchar.c
index 0e4e3c315..475bfca8e 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -52,7 +52,7 @@ static int typeahead_char = 0; /* typeahead char that's not flushed */
*/
static int block_redo = FALSE;
-static int KeyNoremap = 0; /* remapping flags */
+static int KeyNoremap = 0; // remapping flags
/*
* Variables used by vgetorpeek() and flush_buffers().
@@ -1771,7 +1771,7 @@ vgetc(void)
if (!no_reduce_keys)
{
// A modifier was not used for a mapping, apply it to ASCII
- // keys.
+ // keys. Shift would already have been applied.
if ((mod_mask & MOD_MASK_CTRL)
&& ((c >= '`' && c <= 0x7f)
|| (c >= '@' && c <= '_')))
@@ -2240,6 +2240,7 @@ handle_mapping(
// Skip ":lmap" mappings if keys were mapped.
if (mp->m_keys[0] == tb_c1
&& (mp->m_mode & local_State)
+ && !(mp->m_simplified && seenModifyOtherKeys)
&& ((mp->m_mode & LANGMAP) == 0 || typebuf.tb_maplen == 0))
{
#ifdef FEAT_LANGMAP
diff --git a/src/globals.h b/src/globals.h
index d790c82e7..014fca2ad 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1002,6 +1002,10 @@ EXTERN int ex_no_reprint INIT(= FALSE); // no need to print after z or p
EXTERN int reg_recording INIT(= 0); // register for recording or zero
EXTERN int reg_executing INIT(= 0); // register being executed or zero
+// Set when a modifyOtherKeys sequence was seen, then simplified mappings will
+// no longer be used.
+EXTERN int seenModifyOtherKeys INIT(= FALSE);
+
EXTERN int no_mapping INIT(= FALSE); // currently no mapping allowed
EXTERN int no_zero_mapping INIT(= 0); // mapping zero not allowed
EXTERN int allow_keys INIT(= FALSE); // allow key codes when no_mapping
diff --git a/src/gui_mac.c b/src/gui_mac.c
index b43ed8506..185cdee28 100644
--- a/src/gui_mac.c
+++ b/src/gui_mac.c
@@ -2177,7 +2177,8 @@ gui_mac_unicode_key_event(
key_char = simplify_key(key_char, (int *)&vimModifiers);
/* Interpret META, include SHIFT, etc. */
- key_char = extract_modifiers(key_char, (int *)&vimModifiers);
+ key_char = extract_modifiers(key_char, (int *)&vimModifiers,
+ TRUE, NULL);
if (key_char == CSI)
key_char = K_CSI;
@@ -4772,7 +4773,8 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx)
char_u *p_actext;
p_actext = menu->actext;
- key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE);
+ key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE,
+ TRUE, NULL);
if (*p_actext != 0)
key = 0; /* error: trailing text */
/* find_special_key() returns a keycode with as many of the
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 61b09e139..ae47873e4 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -850,7 +850,7 @@ _OnSysChar(
modifiers &= ~MOD_MASK_SHIFT;
/* Interpret the ALT key as making the key META, include SHIFT, etc. */
- ch = extract_modifiers(ch, &modifiers);
+ ch = extract_modifiers(ch, &modifiers, TRUE, NULL);
if (ch == CSI)
ch = K_CSI;
diff --git a/src/highlight.c b/src/highlight.c
index 0fdd93a26..1333362db 100644
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -1417,7 +1417,8 @@ do_highlight(
*/
for (p = arg, off = 0; off < 100 - 6 && *p; )
{
- len = trans_special(&p, buf + off, FALSE, FALSE);
+ len = trans_special(&p, buf + off, FALSE, FALSE,
+ TRUE, NULL);
if (len > 0) // recognized special char
off += len;
else // copy as normal char
diff --git a/src/if_ole.cpp b/src/if_ole.cpp
index cb643e546..34ce23266 100644
--- a/src/if_ole.cpp
+++ b/src/if_ole.cpp
@@ -330,7 +330,7 @@ CVim::SendKeys(BSTR keys)
}
/* Translate key codes like <Esc> */
- str = replace_termcodes((char_u *)buffer, &ptr, FALSE, TRUE, FALSE);
+ str = replace_termcodes((char_u *)buffer, &ptr, REPTERM_DO_LT, NULL);
/* If ptr was set, then a new buffer was allocated,
* so we can free the old one.
diff --git a/src/main.c b/src/main.c
index 33ac89c09..5545cc48a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4339,7 +4339,7 @@ server_to_input_buf(char_u *str)
* <lt> sequence is recognised - needed for a real backslash.
*/
p_cpo = (char_u *)"Bk";
- str = replace_termcodes((char_u *)str, &ptr, FALSE, TRUE, FALSE);
+ str = replace_termcodes((char_u *)str, &ptr, REPTERM_DO_LT, NULL);
p_cpo = cpo_save;
if (*ptr != NUL) /* trailing CTRL-V results in nothing */
diff --git a/src/map.c b/src/map.c
index df8cbedb1..00f4608b0 100644
--- a/src/map.c
+++ b/src/map.c
@@ -256,18 +256,15 @@ do_map(
char_u *p;
int n;
int len = 0; // init for GCC
- char_u *newstr;
int hasarg;
int haskey;
- int did_it = FALSE;
- int did_local = FALSE;
- int round;
+ int do_print;
+ int keyround;
char_u *keys_buf = NULL;
+ char_u *alt_keys_buf = NULL;
char_u *arg_buf = NULL;
int retval = 0;
int do_backslash;
- int hash;
- int new_hash;
mapblock_T **abbr_table;
mapblock_T **map_table;
int unique = FALSE;
@@ -277,6 +274,7 @@ do_map(
#ifdef FEAT_EVAL
int expr = FALSE;
#endif
+ int did_simplify = FALSE;
int noremap;
char_u *orig_rhs;
@@ -375,6 +373,7 @@ do_map(
rhs = p;
hasarg = (*rhs != NUL);
haskey = (*keys != NUL);
+ do_print = !haskey || (maptype != 1 && !hasarg);
// check for :unmap without argument
if (maptype == 1 && !haskey)
@@ -389,373 +388,427 @@ do_map(
// replace_termcodes() may move the result to allocated memory, which
// needs to be freed later (*keys_buf and *arg_buf).
// replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
+ // If something like <C-H> is simplified to 0x08 then mark it as simplified
+ // and also add a n entry with a modifier, which will work when
+ // modifyOtherKeys is working.
if (haskey)
- keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, special);
+ {
+ char_u *new_keys;
+ int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
+
+ if (special)
+ flags |= REPTERM_SPECIAL;
+ new_keys = replace_termcodes(keys, &keys_buf, flags, &did_simplify);
+ if (did_simplify)
+ (void)replace_termcodes(keys, &alt_keys_buf,
+ flags | REPTERM_NO_SIMPLIFY, NULL);
+ keys = new_keys;
+ }
orig_rhs = rhs;
if (hasarg)
{
if (STRICMP(rhs, "<nop>") == 0) // "<Nop>" means nothing
rhs = (char_u *)"";
else
- rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE, special);
+ rhs = replace_termcodes(rhs, &arg_buf,
+ REPTERM_DO_LT | (special ? REPTERM_SPECIAL : 0), NULL);
}
- // check arguments and translate function keys
- if (haskey)
+ /*
+ * The following is done twice if we have two versions of keys:
+ * "alt_keys_buf" is not NULL.
+ */
+ for (keyround = 1; keyround <= 2; ++keyround)
{
- len = (int)STRLEN(keys);
- if (len > MAXMAPLEN) // maximum length of MAXMAPLEN chars
+ int did_it = FALSE;
+ int did_local = FALSE;
+ int round;
+ int hash;
+ int new_hash;
+
+ if (keyround == 2)
{
- retval = 1;
- goto theend;
+ if (alt_keys_buf == NULL)
+ break;
+ keys = alt_keys_buf;
}
+ else if (alt_keys_buf != NULL && do_print)
+ // when printing always use the not-simplified map
+ keys = alt_keys_buf;
- if (abbrev && maptype != 1)
+ // check arguments and translate function keys
+ if (haskey)
{
- // 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.
- if (has_mbyte)
+ len = (int)STRLEN(keys);
+ if (len > MAXMAPLEN) // maximum length of MAXMAPLEN chars
{
- int first, last;
- int same = -1;
-
- first = vim_iswordp(keys);
- last = first;
- p = keys + (*mb_ptr2len)(keys);
- n = 1;
- while (p < keys + 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 += (*mb_ptr2len)(p);
- }
- if (last && n > 2 && same >= 0 && same < n - 1)
+ retval = 1;
+ goto theend;
+ }
+
+ if (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.
+ if (has_mbyte)
{
- retval = 1;
- goto theend;
+ int first, last;
+ int same = -1;
+
+ first = vim_iswordp(keys);
+ last = first;
+ p = keys + (*mb_ptr2len)(keys);
+ n = 1;
+ while (p < keys + 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 += (*mb_ptr2len)(p);
+ }
+ if (last && n > 2 && same >= 0 && same < n - 1)
+ {
+ retval = 1;
+ goto theend;
+ }
}
- }
- else if (vim_iswordc(keys[len - 1])) // ends in keyword char
+ else if (vim_iswordc(keys[len - 1]))
+ // ends in keyword char
for (n = 0; n < len - 2; ++n)
if (vim_iswordc(keys[n]) != vim_iswordc(keys[len - 2]))
{
retval = 1;
goto theend;
}
- // An abbreviation cannot contain white space.
- for (n = 0; n < len; ++n)
- if (VIM_ISWHITE(keys[n]))
- {
- retval = 1;
- goto theend;
- }
+ // An abbreviation cannot contain white space.
+ for (n = 0; n < len; ++n)
+ if (VIM_ISWHITE(keys[n]))
+ {
+ retval = 1;
+ goto theend;
+ }
+ }
}
- }
- if (haskey && hasarg && abbrev) // if we will add an abbreviation
- no_abbr = FALSE; // reset flag that indicates there are
+ if (haskey && hasarg && abbrev) // if we will add an abbreviation
+ no_abbr = FALSE; // reset flag that indicates there are
// no abbreviations
- if (!haskey || (maptype != 1 && !hasarg))
- msg_start();
+ if (do_print)
+ msg_start();
- // Check if a new local mapping wasn't already defined globally.
- if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
- {
- // need to loop over all global hash lists
- for (hash = 0; hash < 256 && !got_int; ++hash)
+ // Check if a new local mapping wasn't already defined globally.
+ if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
{
- if (abbrev)
- {
- if (hash != 0) // there is only one abbreviation list
- break;
- mp = first_abbr;
- }
- else
- mp = maphash[hash];
- for ( ; mp != NULL && !got_int; mp = mp->m_next)
+ // need to loop over all global hash lists
+ for (hash = 0; hash < 256 && !got_int; ++hash)
{
- // check entries with the same mode
- if ((mp->m_mode & mode) != 0
- && mp->m_keylen == len
- && unique
- && STRNCMP(mp->m_keys, keys, (size_t)len) == 0)
+ if (abbrev)
{
- if (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;
+ if (hash != 0) // there is only one abbreviation list
+ break;
+ 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
+ && unique
+ && STRNCMP(mp->m_keys, keys, (size_t)len) == 0)
+ {
+ if (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;
+ }
}
}
}
- }
- // When listing global mappings, also list buffer-local ones here.
- if (map_table != curbuf->b_maphash && !hasarg && maptype != 1)
- {
- // need to loop over all global hash lists
- for (hash = 0; hash < 256 && !got_int; ++hash)
+ // When listing global mappings, also list buffer-local ones here.
+ if (map_table != curbuf->b_maphash && !hasarg && maptype != 1)
{
- if (abbrev)
- {
- if (hash != 0) // there is only one abbreviation list
- break;
- mp = curbuf->b_first_abbr;
- }
- else
- mp = curbuf->b_maphash[hash];
- for ( ; mp != NULL && !got_int; mp = mp->m_next)
+ // need to loop over all global hash lists
+ for (hash = 0; hash < 256 && !got_int; ++hash)
{
- // check entries with the same mode
- if ((mp->m_mode & mode) != 0)
+ if (abbrev)
{
- if (!haskey) // show all entries
- {
- showmap(mp, TRUE);
- did_local = TRUE;
- }
- else
+ if (hash != 0) // there is only one abbreviation list
+ break;
+ mp = curbuf->b_first_abbr;
+ }
+ else
+ mp = curbuf->b_maphash[hash];
+ for ( ; mp != NULL && !got_int; mp = mp->m_next)
+ {
+ // check entries with the same mode
+ if ((mp->m_mode & mode) != 0)
{
- n = mp->m_keylen;
- if (STRNCMP(mp->m_keys, keys,
- (size_t)(n < len ? n : len)) == 0)
+ if (!haskey) // show all entries
{
showmap(mp, TRUE);
did_local = TRUE;
}
+ else
+ {
+ n = mp->m_keylen;
+ if (STRNCMP(mp->m_keys, keys,
+ (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)
+ // 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)
{
- if (abbrev)
+ // need to loop over all hash lists
+ for (hash = 0; hash < 256 && !got_int; ++hash)
{
- 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
+ if (abbrev)
{
- mpp = &(mp->m_next);
- continue;
- }
- if (!haskey) // show all entries
- {
- showmap(mp, map_table != maphash);
- did_it = TRUE;
+ if (hash > 0) // there is only one abbreviation list
+ break;
+ mpp = abbr_table;
}
- else // do we have a match?
+ else
+ mpp = &(map_table[hash]);
+ for (mp = *mpp; mp != NULL && !got_int; mp = *mpp)
{
- if (round) // second round: Try unmap "rhs" string
+
+ if (!(mp->m_mode & mode)) // skip entries with wrong mode
{
- n = (int)STRLEN(mp->m_str);
- p = mp->m_str;
+ mpp = &(mp->m_next);
+ continue;
}
- else
+ if (!haskey) // show all entries
{
- n = mp->m_keylen;
- p = mp->m_keys;
+ showmap(mp, map_table != maphash);
+ did_it = TRUE;
}
- if (STRNCMP(p, keys, (size_t)(n < len ? n : len)) == 0)
+ else // do we have a match?
{
- if (maptype == 1) // delete entry
+ if (round) // second round: Try unmap "rhs" string
{
- // 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 && (!abbrev || round || n > len
+ n = (int)STRLEN(mp->m_str);
+ p = mp->m_str;
+ }
+ else
+ {
+ n = mp->m_keylen;
+ p = mp->m_keys;
+ }
+ if (STRNCMP(p, keys, (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 && (!abbrev || round || n > len
|| *skipwhite(keys + 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 (!hasarg) // 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 (!hasarg) // 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 (unique)
- {
- if (abbrev)
- semsg(_("E226: abbreviation already exists for %s"),
- p);
+ else if (unique)
+ {
+ if (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
{
- newstr = vim_strsave(rhs);
- if (newstr == NULL)
+ // new rhs for existing entry
+ mp->m_mode &= ~mode; // remove mode bits
+ if (mp->m_mode == 0 && !did_it) // reuse entry
{
- retval = 4; // no mem
- goto theend;
- }
- vim_free(mp->m_str);
- mp->m_str = newstr;
- vim_free(mp->m_orig_str);
- mp->m_orig_str = vim_strsave(orig_rhs);
- mp->m_noremap = noremap;
- mp->m_nowait = nowait;
- mp->m_silent = silent;
- mp->m_mode = mode;
+ char_u *newstr = vim_strsave(rhs);
+
+ if (newstr == NULL)
+ {
+ retval = 4; // no mem
+ goto theend;
+ }
+ vim_free(mp->m_str);
+ mp->m_str = newstr;
+ vim_free(mp->m_orig_str);
+ mp->m_orig_str = vim_strsave(orig_rhs);
+ mp->m_noremap = noremap;
+ mp->m_nowait = nowait;
+ mp->m_silent = silent;
+ mp->m_mode = mode;
+ mp->m_simplified =
+ did_simplify && keyround == 1;
#ifdef FEAT_EVAL
- mp->m_expr = expr;
- mp->m_script_ctx = current_sctx;
- mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ mp->m_expr = expr;
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
#endif
- did_it = TRUE;
+ did_it = TRUE;
+ }
+ }
+ if (mp->m_mode == 0) // entry can be deleted
+ {
+ map_free(mpp);
+ continue; // continue with *mpp
}
- }
- if (mp->m_mode == 0) // entry can be deleted
- {
- map_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 (!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.
+ new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ if (!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 (*keys == Ctrl_C)
+ if (maptype == 1)
{
- // If CTRL-C has been unmapped, reuse it for Interrupting.
- if (map_table == curbuf->b_maphash)
- curbuf->b_mapped_ctrl_c &= ~mode;
- else
- mapped_ctrl_c &= ~mode;
+ // delete entry
+ if (!did_it)
+ retval = 2; // no match
+ else if (*keys == Ctrl_C)
+ {
+ // If CTRL-C has been unmapped, reuse it for Interrupting.
+ if (map_table == curbuf->b_maphash)
+ curbuf->b_mapped_ctrl_c &= ~mode;
+ else
+ mapped_ctrl_c &= ~mode;
+ }
+ continue;
}
- goto theend;
- }
- if (!haskey || !hasarg) // print entries
- {
- if (!did_it && !did_local)
+ if (!haskey || !hasarg)
{
- if (abbrev)
- msg(_("No abbreviation found"));
- else
- msg(_("No mapping found"));
+ // print entries
+ if (!did_it && !did_local)
+ {
+ if (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 = ALLOC_ONE(mapblock_T);
- if (mp == NULL)
- {
- retval = 4; // no mem
- goto theend;
- }
+ // Get here when adding a new entry to the maphash[] list or abbrlist.
+ mp = ALLOC_ONE(mapblock_T);
+ if (mp == NULL)
+ {
+ retval = 4; // no mem
+ goto theend;
+ }
- // If CTRL-C has been mapped, don't always use it for Interrupting.
- if (*keys == Ctrl_C)
- {
- if (map_table == curbuf->b_maphash)
- curbuf->b_mapped_ctrl_c |= mode;
- else
- mapped_ctrl_c |= mode;
- }
+ // If CTRL-C has been mapped, don't always use it for Interrupting.
+ if (*keys == Ctrl_C)
+ {
+ if (map_table == curbuf->b_maphash)
+ curbuf->b_mapped_ctrl_c |= mode;
+ else
+ mapped_ctrl_c |= mode;
+ }
- mp->m_keys = vim_strsave(keys);
- mp->m_str = vim_strsave(rhs);
- mp->m_orig_str = vim_strsave(orig_rhs);
- if (mp->m_keys == NULL || mp->m_str == NULL)
- {
- vim_free(mp->m_keys);
- vim_free(mp->m_str);
- vim_free(mp->m_orig_str);
- vim_free(mp);
- retval = 4; // no mem
- goto theend;
- }
- mp->m_keylen = (int)STRLEN(mp->m_keys);
- mp->m_noremap = noremap;
- mp->m_nowait = nowait;
- mp->m_silent = silent;
- mp->m_mode = mode;
+ mp->m_keys = vim_strsave(keys);
+ mp->m_str = vim_strsave(rhs);
+ mp->m_orig_str = vim_strsave(orig_rhs);
+ if (mp->m_keys == NULL || mp->m_str == NULL)
+ {
+ vim_free(mp->m_keys);
+ vim_free(mp->m_str);
+ vim_free(mp->m_orig_str);
+ vim_free(mp);
+ retval = 4; // no mem
+ goto theend;
+ }
+ mp->m_keylen = (int)STRLEN(mp->m_keys);
+ mp->m_noremap = noremap;
+ mp->m_nowait = nowait;
+ mp->m_silent = silent;
+ mp->m_mode = mode;
+ mp->m_simplified = did_simplify && keyround == 1;
#ifdef FEAT_EVAL
- mp->m_expr = expr;
- mp->m_script_ctx = current_sctx;
- mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ mp->m_expr = expr;
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
#endif
- // add the new entry in front of the abbrlist or maphash[] list
- if (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;
+ // add the new entry in front of the abbrlist or maphash[] list
+ if (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:
vim_free(keys_buf);
+ vim_free(alt_keys_buf);
vim_free(arg_buf);
return retval;
}
@@ -934,7 +987,7 @@ map_to_exists(char_u *str, char_u *modechars, int abbr)
char_u *buf;
int retval;
- rhs = replace_termcodes(str, &buf, FALSE, TRUE, FALSE);
+ rhs = replace_termcodes(str, &buf, REPTERM_DO_LT, NULL);
retval = map_to_exists_mode(rhs, mode_str2flags(modechars), abbr);
vim_free(buf);
@@ -2036,7 +2089,8 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact)
mode = get_map_mode(&which, 0);
- keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
+ keys = replace_termcodes(keys, &keys_buf,
+ REPTERM_FROM_PART | REPTERM_DO_LT, NULL);
rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
vim_free(keys_buf);
diff --git a/src/menu.c b/src/menu.c
index 4096a0571..e55cab675 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -372,7 +372,8 @@ ex_menu(
else if (modes & MENU_TIP_MODE)
map_buf = NULL; /* Menu tips are plain text. */
else
- map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special);
+ map_to = replace_termcodes(map_to, &map_buf,
+ REPTERM_DO_LT | (special ? REPTERM_SPECIAL : 0), NULL);
menuarg.modes = modes;
#ifdef FEAT_TOOLBAR
menuarg.iconfile = icon;
diff --git a/src/misc2.c b/src/misc2.c
index 3261437db..67fa8b5ee 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -2696,12 +2696,15 @@ trans_special(
char_u **srcp,
char_u *dst,
int keycode, // prefer key code, e.g. K_DEL instead of DEL
- int in_string) // TRUE when inside a double quoted string
+ int in_string, // TRUE when inside a double quoted string
+ int simplify, // simplify <C-H> and <A-x>
+ int *did_simplify) // found <C-H> or <A-x>
{
int modifiers = 0;
int key;
- key = find_special_key(srcp, &modifiers, keycode, FALSE, in_string);
+ key = find_special_key(srcp, &modifiers, keycode, FALSE, in_string,
+ simplify, did_simplify);
if (key == 0)
return 0;
@@ -2753,9 +2756,11 @@ special_to_buf(int key, int modifiers, int keycode, char_u *dst)
find_special_key(
char_u **srcp,
int *modp,
- int keycode, /* prefer key code, e.g. K_DEL instead of DEL */
- int keep_x_key, /* don't translate xHome to Home key */
- int in_string) /* TRUE in string, double quote is escaped */
+ int keycode, // prefer key code, e.g. K_DEL instead of DEL
+ int keep_x_key, // don't translate xHome to Home key
+ int in_string, // TRUE in string, double quote is escaped
+ int simplify, // simplify <C-H> and <A-x>
+ int *did_simplify) // found <C-H> or <A-x>
{
char_u *last_dash;
char_u *end_of_name;
@@ -2835,7 +2840,8 @@ find_special_key(
&& VIM_ISDIGIT(last_dash[6]))
{
/* <Char-123> or <Char-033> or <Char-0x33> */
- vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, TRUE);
+ vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL,
+ &n, 0, TRUE);
if (l == 0)
{
emsg(_(e_invarg));
@@ -2885,11 +2891,10 @@ find_special_key(
key = DEL;
}
- /*
- * Normal Key with modifier: Try to make a single byte code.
- */
+ // Normal Key with modifier: Try to make a single byte code.
if (!IS_SPECIAL(key))
- key = extract_modifiers(key, &modifiers);
+ key = extract_modifiers(key, &modifiers,
+ simplify, did_simplify);
*modp = modifiers;
*srcp = end_of_name;
@@ -2903,26 +2908,37 @@ find_special_key(
/*
* Try to include modifiers in the key.
* Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
+ * When "simplify" is FALSE don't do Ctrl and Alt.
+ * When "simplify" is TRUE and Ctrl or Alt is removed from modifiers set
+ * "did_simplify" when it's not NULL.
*/
int
-extract_modifiers(int key, int *modp)
+extract_modifiers(int key, int *modp, int simplify, int *did_simplify)
{
int modifiers = *modp;
#ifdef MACOS_X
- /* Command-key really special, no fancynest */
+ // Command-key really special, no fancynest
if (!(modifiers & MOD_MASK_CMD))
#endif
if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key))
{
key = TOUPPER_ASC(key);
- modifiers &= ~MOD_MASK_SHIFT;
+ // With <C-S-a> and <A-S-a> we keep the shift modifier.
+ // With <S-a> and <S-A> we don't keep the shift modifier.
+ if (simplify || modifiers == MOD_MASK_SHIFT)
+ modifiers &= ~MOD_MASK_SHIFT;
}
- if ((modifiers & MOD_MASK_CTRL)
+
+ // <C-H> and <C-h> mean the same thing, always use "H"
+ if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
+ key = TOUPPER_ASC(key);
+
+ if (simplify && (modifiers & MOD_MASK_CTRL)
#ifdef EBCDIC
- /* * TODO: EBCDIC Better use:
- * && (Ctrl_chr(key) || key == '?')
- * ??? */
+ // TODO: EBCDIC Better use:
+ // && (Ctrl_chr(key) || key == '?')
+ // ???
&& strchr("?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_", key)
!= NULL
#else
@@ -2935,16 +2951,21 @@ extract_modifiers(int key, int *modp)
/* <C-@> is <Nul> */
if (key == 0)
key = K_ZERO;
+ if (did_simplify != NULL)
+ *did_simplify = TRUE;
}
+
#ifdef MACOS_X
/* Command-key really special, no fancynest */
if (!(modifiers & MOD_MASK_CMD))
#endif
- if ((modifiers & MOD_MASK_ALT) && key < 0x80
+ if (simplify && (modifiers & MOD_MASK_ALT) && key < 0x80
&& !enc_dbcs) // avoid creating a lead byte
{
key |= 0x80;
modifiers &= ~MOD_MASK_ALT; /* remove the META modifier */
+ if (did_simplify != NULL)
+ *did_simplify = TRUE;
}
*modp = modifiers;
diff --git a/src/option.c b/src/option.c
index 60c1141b6..898068b41 100644
--- a/src/option.c
+++ b/src/option.c
@@ -4495,7 +4495,7 @@ find_key_option(char_u *arg_arg, int has_lt)
{
--arg; /* put arg at the '<' */
modifiers = 0;
- key = find_special_key(&arg, &modifiers, TRUE, TRUE, FALSE);
+ key = find_special_key(&arg, &modifiers, TRUE, TRUE, FALSE, TRUE, NULL);
if (modifiers) /* can't handle modifiers here */
key = 0;
}
diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro
index bcdcd3147..a52b46280 100644
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -67,10 +67,10 @@ void append_ga_line(garray_T *gap);
int simplify_key(int key, int *modifiers);
int handle_x_keys(int key);
char_u *get_special_key_name(int c, int modifiers);
-int trans_special(char_u **srcp, char_u *dst, int keycode, int in_string);
+int trans_special(char_u **srcp, char_u *dst, int keycode, int in_string, int simplify, int *did_simplify);
int special_to_buf(int key, int modifiers, int keycode, char_u *dst);
-int find_special_key(char_u **srcp, int *modp, int keycode, int keep_x_key, int in_string);
-int extract_modifiers(int key, int *modp);
+int find_special_key(char_u **srcp, int *modp, int keycode, int keep_x_key, int in_string, int simplify, int *did_simplify);
+int extract_modifiers(int key, int *modp, int simplify, int *did_simplify);
int find_special_key_in_table(int c);
int get_special_key_code(char_u *name);
char_u *get_key_name(int i);
diff --git a/src/proto/term.pro b/src/proto/term.pro
index a7a051c34..b29eace07 100644
--- a/src/proto/term.pro
+++ b/src/proto/term.pro
@@ -67,7 +67,7 @@ int is_mouse_topline(win_T *wp);
int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen);
void term_get_fg_color(char_u *r, char_u *g, char_u *b);
void term_get_bg_color(char_u *r, char_u *g, char_u *b);
-char_u *replace_termcodes(char_u *from, char_u **bufp, int from_part, int do_lt, int special);
+char_u *replace_termcodes(char_u *from, char_u **bufp, int flags, int *did_simplify);
void show_termcodes(void);
int show_one_termcode(char_u *name, char_u *code, int printit);
char_u *translate_mapping(char_u *str);
diff --git a/src/structs.h b/src/structs.h
index 2d7c4fd88..7c0bfce8f 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1172,6 +1172,8 @@ struct mapblock
char_u *m_orig_str; // rhs as entered by the user
int m_keylen; // strlen(m_keys)
int m_mode; // valid mode
+ int m_simplified; // m_keys was simplified, do not use this map
+ // if seenModifyOtherKeys is TRUE
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/term.c b/src/term.c
index 8ab5f4271..2158fe37f 100644
--- a/src/term.c
+++ b/src/term.c
@@ -4845,6 +4845,7 @@ not_enough:
else if ((arg[0] == 27 && argc == 3 && trail == '~')
|| (argc == 2 && trail == 'u'))
{
+ seenModifyOtherKeys = TRUE;
if (trail == 'u')
key = arg[0];
else
@@ -4853,13 +4854,20 @@ not_enough:
modifiers = decode_modifiers(arg[1]);
// Some keys already have Shift included, pass them as
- // normal keys.
+ // normal keys. Not when Ctrl is also used, because <C-H>
+ // and <C-S-H> are different.
if (modifiers == MOD_MASK_SHIFT
&& ((key >= '@' && key <= 'Z')
|| key == '^' || key == '_'
|| (key >= '{' && key <= '~')))
modifiers = 0;
+ // When used with Ctrl we always make a letter upper case,
+ // so that mapping <C-H> and <C-h> are the same. Typing
+ // <C-S-H> also uses "H" but modifier is different.
+ if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
+ key = TOUPPER_ASC(key);
+
// insert modifiers with KS_MODIFIER
new_slen = modifiers2keycode(modifiers, &key, string);
slen = csi_len;
@@ -5340,18 +5348,26 @@ term_get_bg_color(char_u *r, char_u *g, char_u *b)
* pointer to it is returned. If something fails *bufp is set to NULL and from
* is returned.
*
- * CTRL-V characters are removed. When "from_part" is TRUE, a trailing CTRL-V
- * is included, otherwise it is removed (for ":map xx ^V", maps xx to
- * nothing). When 'cpoptions' does not contain 'B', a backslash can be used
- * instead of a CTRL-V.
+ * CTRL-V characters are removed. When "flags" has REPTERM_FROM_PART, a
+ * trailing CTRL-V is included, otherwise it is removed (for ":map xx ^V", maps
+ * xx to nothing). When 'cpoptions' does not contain 'B', a backslash can be
+ * used instead of a CTRL-V.
+ *
+ * Flags:
+ * REPTERM_FROM_PART see above
+ * REPTERM_DO_LT also translate <lt>
+ * REPTERM_SPECIAL always accept <key> notation
+ * REPTERM_NO_SIMPLIFY do not simplify <C-H> to 0x08 and set 8th bit for <A-x>
+ *
+ * "did_simplify" is set when some <C-H> or <A-x> code was simplified, unless
+ * it is NULL.
*/
char_u *
replace_termcodes(
char_u *from,
char_u **bufp,
- int from_part,
- int do_lt, /* also translate <lt> */
- int special) /* always accept <key> notation */
+ int flags,
+ int *did_simplify)
{
int i;
int slen;
@@ -5364,7 +5380,8 @@ replace_termcodes(
char_u *result; /* buffer for resulting string */
do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
- do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL) || special;
+ do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL)
+ || (flags & REPTERM_SPECIAL);
do_key_code = (vim_strchr(p_cpo, CPO_KEYCODE) == NULL);
/*
@@ -5383,7 +5400,7 @@ replace_termcodes(
/*
* Check for #n at start only: function key n
*/
- if (from_part && src[0] == '#' && VIM_ISDIGIT(src[1])) /* function key */
+ if ((flags & REPTERM_FROM_PART) && src[0] == '#' && VIM_ISDIGIT(src[1]))
{
result[dlen++] = K_SPECIAL;
result[dlen++] = 'k';
@@ -5403,7 +5420,8 @@ replace_termcodes(
* If 'cpoptions' does not contain '<', check for special key codes,
* like "<C-S-LeftMouse>"
*/
- if (do_special && (do_lt || STRNCMP(src, "<lt>", 4) != 0))
+ if (do_special && ((flags & REPTERM_DO_LT)
+ || STRNCMP(src, "<lt>", 4) != 0))
{
#ifdef FEAT_EVAL
/*
@@ -5429,7 +5447,8 @@ replace_termcodes(
}
#endif
- slen = trans_special(&src, result + dlen, TRUE, FALSE);
+ slen = trans_special(&src, result + dlen, TRUE, FALSE,
+ (flags & REPTERM_NO_SIMPLIFY) == 0, did_simplify);
if (slen)
{
dlen += slen;
@@ -5509,7 +5528,7 @@ replace_termcodes(
++src; /* skip CTRL-V or backslash */
if (*src == NUL)
{
- if (from_part)
+ if (flags & REPTERM_FROM_PART)
result[dlen++] = key;
break;
}
diff --git a/src/terminal.c b/src/terminal.c
index a992b444d..7b2d43bf2 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -772,7 +772,8 @@ ex_terminal(exarg_T *eap)
p = skiptowhite(cmd);
*p = NUL;
- keys = replace_termcodes(ep + 1, &buf, TRUE, TRUE, TRUE);
+ keys = replace_termcodes(ep + 1, &buf,
+ REPTERM_FROM_PART | REPTERM_DO_LT | REPTERM_SPECIAL, NULL);
opt.jo_set2 |= JO2_EOF_CHARS;
opt.jo_eof_chars = vim_strsave(keys);
vim_free(buf);
@@ -1372,7 +1373,12 @@ term_convert_key(term_T *term, int c, char *buf)
}
// add modifiers for the typed key
- mod |= mod_mask;
+ if (mod_mask & MOD_MASK_SHIFT)
+ mod |= VTERM_MOD_SHIFT;
+ if (mod_mask & MOD_MASK_CTRL)
+ mod |= VTERM_MOD_CTRL;
+ if (mod_mask & (MOD_MASK_ALT | MOD_MASK_META))
+ mod |= VTERM_MOD_ALT;
/*
* Convert special keys to vterm keys:
diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim
index 1df9f7bf1..8fe1850eb 100644
--- a/src/testdir/test_termcodes.vim
+++ b/src/testdir/test_termcodes.vim
@@ -862,7 +862,7 @@ endfunc
" The mode doesn't need to be enabled, the codes are always detected.
func RunTest_modifyOtherKeys(func)
new
- set timeoutlen=20
+ set timeoutlen=10
" Shift-X is send as 'X' with the shift modifier
call feedkeys('a' .. a:func('X', 2) .. "\<Esc>", 'Lx!')
@@ -902,11 +902,8 @@ func RunTest_modifyOtherKeys(func)
set timeoutlen&
endfunc
-func Test_modifyOtherKeys_CSI27()
+func Test_modifyOtherKeys_basic()
call RunTest_modifyOtherKeys(function('GetEscCodeCSI27'))
-endfunc
-
-func Test_modifyOtherKeys_CSIu()
call RunTest_modifyOtherKeys(function('GetEscCodeCSIu'))
endfunc
@@ -928,7 +925,7 @@ endfunc
func RunTest_mapping_works_with_shift(func)
new
- set timeoutlen=20
+ set timeoutlen=10
call RunTest_mapping_shift('@', a:func)
call RunTest_mapping_shift('A', a:func)
@@ -944,7 +941,88 @@ func RunTest_mapping_works_with_shift(func)
set timeoutlen&
endfunc
-func Test_mapping_works_with_shift()
+func Test_mapping_works_with_shift_plain()
call RunTest_mapping_works_with_shift(function('GetEscCodeCSI27'))
call RunTest_mapping_works_with_shift(function('GetEscCodeCSIu'))
endfunc
+
+func RunTest_mapping_mods(map, key, func, code)
+ call setline(1, '')
+ exe 'inoremap ' .. a:map .. ' xyz'
+ call feedkeys('a' .. a:func(a:key, a:code) .. "\<Esc>", 'Lx!')
+ call assert_equal("xyz", getline(1))
+ exe 'iunmap ' .. a:map
+endfunc
+
+func RunTest_mapping_works_with_mods(func, mods, code)
+ new
+ set timeoutlen=10
+
+ if a:mods !~ 'S'
+ " Shift by itself has no effect
+ call RunTest_mapping_mods('<' .. a:mods .. '-@>', '@', a:func, a:code)
+ endif
+ call RunTest_mapping_mods('<' .. a:mods .. '-A>', 'A', a:func, a:code)
+ call RunTest_mapping_mods('<' .. a:mods .. '-Z>', 'Z', a:func, a:code)
+ if a:mods !~ 'S'
+ " with Shift code is always upper case
+ call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'a', a:func, a:code)
+ call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'z', a:func, a:code)
+ endif
+ if a:mods != 'A'
+ " with Alt code is not in upper case
+ call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'A', a:func, a:code)
+ call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'Z', a:func, a:code)
+ endif
+ call RunTest_mapping_mods('<' .. a:mods .. '-á>', 'á', a:func, a:code)
+ if a:mods !~ 'S'
+ " Shift by itself has no effect
+ call RunTest_mapping_mods('<' .. a:mods .. '-^>', '^', a:func, a:code)
+ call RunTest_mapping_mods('<' .. a:mods .. '-_>', '_', a:func, a:code)
+ call RunTest_mapping_mods('<' .. a:mods .. '-{>', '{', a:func, a:code)
+ call RunTest_mapping_mods('<' .. a:mods .. '-\|>', '|', a:func, a:code)
+ call RunTest_mapping_mods('<' .. a:mods .. '-}>', '}', a:func, a:code)
+ call RunTest_mapping_mods('<' .. a:mods .. '-~>', '~', a:func, a:code)
+ endif
+
+ bwipe!
+ set timeoutlen&
+endfunc
+
+func Test_mapping_works_with_shift()
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S', 2)
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S', 2)
+endfunc
+
+func Test_mapping_works_with_ctrl()
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C', 5)
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C', 5)
+endfunc
+
+func Test_mapping_works_with_shift_ctrl()
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S', 6)
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S', 6)
+endfunc
+
+" Below we also test the "u" code with Alt, This works, but libvterm would not
+" send the Alt key like this but by prefixing an Esc.
+
+func Test_mapping_works_with_alt()
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'A', 3)
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'A', 3)
+endfunc
+
+func Test_mapping_works_with_shift_alt()
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S-A', 4)
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S-A', 4)
+endfunc
+
+func Test_mapping_works_with_ctrl_alt()
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-A', 7)
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-A', 7)
+endfunc
+
+func Test_mapping_works_with_shift_ctrl_alt()
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S-A', 8)
+ call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S-A', 8)
+endfunc
diff --git a/src/usercmd.c b/src/usercmd.c
index c6bf7fe34..b48f157d6 100644
--- a/src/usercmd.c
+++ b/src/usercmd.c
@@ -868,7 +868,7 @@ uc_add_command(
char_u *rep_buf = NULL;
garray_T *gap;
- replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE);
+ replace_termcodes(rep, &rep_buf, 0, NULL);
if (rep_buf == NULL)
{
// Can't replace termcodes - try using the string as is
diff --git a/src/version.c b/src/version.c
index 8ad31a09c..18509fd0d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2145,
+/**/
2144,
/**/
2143,
diff --git a/src/vim.h b/src/vim.h
index 1d479c692..5a977a8af 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -2633,4 +2633,10 @@ long elapsed(DWORD start_tick);
#define CLIP_ZINDEX 32000
+// Flags for replace_termcodes()
+#define REPTERM_FROM_PART 1
+#define REPTERM_DO_LT 2
+#define REPTERM_SPECIAL 4
+#define REPTERM_NO_SIMPLIFY 8
+
#endif // VIM__H