]> granicus.if.org Git - vim/commitdiff
patch 8.1.2145: cannot map <C-H> when modifyOtherKeys is enabled v8.1.2145
authorBram Moolenaar <Bram@vim.org>
Sun, 13 Oct 2019 14:43:39 +0000 (16:43 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 13 Oct 2019 14:43:39 +0000 (16:43 +0200)
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.

21 files changed:
src/eval.c
src/getchar.c
src/globals.h
src/gui_mac.c
src/gui_w32.c
src/highlight.c
src/if_ole.cpp
src/main.c
src/map.c
src/menu.c
src/misc2.c
src/option.c
src/proto/misc2.pro
src/proto/term.pro
src/structs.h
src/term.c
src/terminal.c
src/testdir/test_termcodes.vim
src/usercmd.c
src/version.c
src/vim.h

index 0fe8fd34aa9cc04fe8c028f8131b82f75b62b3ff..ace1e013f5ebb8eb34d31270305a383856a012cc 100644 (file)
@@ -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;
index 0e4e3c31571baba7c3db8efaf16ad90c060f5048..475bfca8e137aa9a664aecde9e9c038f385c4530 100644 (file)
@@ -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
index d790c82e78d7dec8bd8308fb863c57ae6c563ae5..014fca2ad4a44dfcd985f30210f4cabd305ecebc 100644 (file)
@@ -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
index b43ed8506f50d0d2cee1b5ba55e182ab8eea6fb3..185cdee28e5a4dfeb033ff02a0e49705fd6a9223 100644 (file)
@@ -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
index 61b09e1395a59f6d849949289ff63598a332d47a..ae47873e4effb9065d1461bcace244554de3e709 100644 (file)
@@ -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;
 
index 0fdd93a2671f0ef9b7a119353316ecc75def7fc0..1333362dbd8349113a430957d49eef23c3c70be6 100644 (file)
@@ -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
index cb643e546189def3ce0de4925a99aaf502936368..34ce232660321b490d27ac5d5ab24ec3db182c3e 100644 (file)
@@ -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.
index 33ac89c09730d4ed725403efb03a5cc2b118a701..5545cc48a6eec747fcb0ab607addc9be1baa5f76 100644 (file)
@@ -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 */
index df8cbedb1f2cef260dbb09931f2a28c9834e88c3..00f4608b07917da3a909b0d4d24299be862a2262 100644 (file)
--- 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);
 
index 4096a0571cfa1ae63084d27ae311e3746cea2371..e55cab675842c11d3e3c81ee7698814f6986f9bc 100644 (file)
@@ -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;
index 3261437db24c80f55b0c7062681707af41c73448..67fa8b5eedfbf510e2f9be2f63457146dbf3ad12 100644 (file)
@@ -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;
index 60c1141b6a069fe5fdceecca647b0e87ee21ba3a..898068b416d44190ddb1d68b043e189ef0607d44 100644 (file)
@@ -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;
     }
index bcdcd3147cf8b97b249aa0530980ec5124b1d87e..a52b462804ef628def03a9140e6284b2475f63e4 100644 (file)
@@ -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);
index a7a051c34ad09b6eac9f21d08075bf06d777a6d8..b29eace07aa9369a60adbdac0f1a005330427215 100644 (file)
@@ -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);
index 2d7c4fd8847c671cd3fde76f6ef465510f09b214..7c0bfce8fde3fe1c885a237d66ab5717d2f33cac 100644 (file)
@@ -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
index 8ab5f427102e37e8520455513702ab6a0ee4f98a..2158fe37febce30495c88e22a30e9ca5d2ef542d 100644 (file)
@@ -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;
            }
index a992b444dcd0f3b70882e0fa967821b14379cecd..7b2d43bf256c568dc7423c11f9a073003b9c6d9b 100644 (file)
@@ -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:
index 1df9f7bf118115e54e9e5bf95220ce6232cb0260..8fe1850ebe32d3fd4c2fa872540c0134e775af6e 100644 (file)
@@ -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
index c6bf7fe343ad5c3a7c42f0d87ffe4a4630dc2d7e..b48f157d6209f9ea675bc6bc148deecc464ecfdf 100644 (file)
@@ -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
index 8ad31a09c2c228c6566132ce9a750736e3fb08db..18509fd0da5edf243d6a00225c54f49e8442bd10 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2145,
 /**/
     2144,
 /**/
index 1d479c6925f577eac28a356d195b415d2cb9b2d8..5a977a8afe9b82e7845780c74ac9b3e3d883a5e5 100644 (file)
--- 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