]> granicus.if.org Git - vim/commitdiff
patch 8.1.1794: tests are flaky v8.1.1794
authorBram Moolenaar <Bram@vim.org>
Fri, 2 Aug 2019 20:46:11 +0000 (22:46 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 2 Aug 2019 20:46:11 +0000 (22:46 +0200)
Problem:    Tests are flaky.
Solution:   Undo the change to vgetorpeek().

src/getchar.c
src/version.c

index ea628cb08256c7af232f3892b19b6412148086e1..8c1a01a3e4f003c9871a53df684a41074214bc9b 100644 (file)
@@ -1900,530 +1900,6 @@ char_avail(void)
     return (retval != NUL);
 }
 
-typedef enum {
-    map_result_fail,    // failed, break loop
-    map_result_get,     // get a character from typeahead
-    map_result_retry,   // try to map again
-    map_result_nomatch  // no matching mapping, get char
-} map_result_T;
-
-/*
- * Handle mappings in the typeahead buffer.
- * - When something was mapped, return map_result_retry for recursive mappings.
- * - When nothing mapped and typeahead has a character return map_result_get.
- * - When there is no match yet, return map_result_nomatch, need to get more
- *   typeahead.
- */
-    static int
-handle_mapping(
-           int *keylenp,
-           int *timedout,
-           int *mapdepth)
-{
-    mapblock_T *mp = NULL;
-    mapblock_T *mp2;
-    mapblock_T *mp_match;
-    int                mp_match_len = 0;
-    int                max_mlen = 0;
-    int                tb_c1;
-    int                mlen;
-#ifdef FEAT_LANGMAP
-    int                nolmaplen;
-#endif
-    int                keylen;
-    int                i;
-    int                local_State = get_real_state();
-
-    /*
-     * Check for a mappable key sequence.
-     * Walk through one maphash[] list until we find an
-     * entry that matches.
-     *
-     * Don't look for mappings if:
-     * - no_mapping set: mapping disabled (e.g. for CTRL-V)
-     * - maphash_valid not set: no mappings present.
-     * - typebuf.tb_buf[typebuf.tb_off] should not be remapped
-     * - in insert or cmdline mode and 'paste' option set
-     * - waiting for "hit return to continue" and CR or SPACE
-     *  typed
-     * - waiting for a char with --more--
-     * - in Ctrl-X mode, and we get a valid char for that mode
-     */
-    tb_c1 = typebuf.tb_buf[typebuf.tb_off];
-    if (no_mapping == 0 && is_maphash_valid()
-           && (no_zero_mapping == 0 || tb_c1 != '0')
-           && (typebuf.tb_maplen == 0
-               || (p_remap
-                   && (typebuf.tb_noremap[typebuf.tb_off]
-                                   & (RM_NONE|RM_ABBR)) == 0))
-           && !(p_paste && (State & (INSERT + CMDLINE)))
-           && !(State == HITRETURN && (tb_c1 == CAR || tb_c1 == ' '))
-           && State != ASKMORE
-           && State != CONFIRM
-#ifdef FEAT_INS_EXPAND
-           && !((ctrl_x_mode_not_default()
-                                  && vim_is_ctrl_x_key(tb_c1))
-                   || ((compl_cont_status & CONT_LOCAL)
-                       && (tb_c1 == Ctrl_N || tb_c1 == Ctrl_P)))
-#endif
-           )
-    {
-#ifdef FEAT_LANGMAP
-       if (tb_c1 == K_SPECIAL)
-           nolmaplen = 2;
-       else
-       {
-           LANGMAP_ADJUST(tb_c1,
-                          (State & (CMDLINE | INSERT)) == 0
-                          && get_real_state() != SELECTMODE);
-           nolmaplen = 0;
-       }
-#endif
-       // First try buffer-local mappings.
-       mp = get_buf_maphash_list(local_State, tb_c1);
-       mp2 = get_maphash_list(local_State, tb_c1);
-       if (mp == NULL)
-       {
-           // There are no buffer-local mappings.
-           mp = mp2;
-           mp2 = NULL;
-       }
-       /*
-        * Loop until a partly matching mapping is found or
-        * all (local) mappings have been checked.
-        * The longest full match is remembered in "mp_match".
-        * A full match is only accepted if there is no partly
-        * match, so "aa" and "aaa" can both be mapped.
-        */
-       mp_match = NULL;
-       mp_match_len = 0;
-       for ( ; mp != NULL;
-               mp->m_next == NULL ? (mp = mp2, mp2 = NULL)
-                                  : (mp = mp->m_next))
-       {
-           // Only consider an entry if the first character
-           // matches and it is for the current state.
-           // Skip ":lmap" mappings if keys were mapped.
-           if (mp->m_keys[0] == tb_c1
-                   && (mp->m_mode & local_State)
-                   && ((mp->m_mode & LANGMAP) == 0
-                       || typebuf.tb_maplen == 0))
-           {
-#ifdef FEAT_LANGMAP
-               int     nomap = nolmaplen;
-               int     c2;
-#endif
-               // find the match length of this mapping
-               for (mlen = 1; mlen < typebuf.tb_len; ++mlen)
-               {
-#ifdef FEAT_LANGMAP
-                   c2 = typebuf.tb_buf[typebuf.tb_off + mlen];
-                   if (nomap > 0)
-                       --nomap;
-                   else if (c2 == K_SPECIAL)
-                       nomap = 2;
-                   else
-                       LANGMAP_ADJUST(c2, TRUE);
-                   if (mp->m_keys[mlen] != c2)
-#else
-                   if (mp->m_keys[mlen] !=
-                       typebuf.tb_buf[typebuf.tb_off + mlen])
-#endif
-                       break;
-               }
-
-               // Don't allow mapping the first byte(s) of a
-               // multi-byte char.  Happens when mapping
-               // <M-a> and then changing 'encoding'. Beware
-               // that 0x80 is escaped.
-               {
-                   char_u *p1 = mp->m_keys;
-                   char_u *p2 = mb_unescape(&p1);
-
-                   if (has_mbyte && p2 != NULL
-                         && MB_BYTE2LEN(tb_c1) > MB_PTR2LEN(p2))
-                       mlen = 0;
-               }
-
-               // Check an entry whether it matches.
-               // - Full match: mlen == keylen
-               // - Partly match: mlen == typebuf.tb_len
-               keylen = mp->m_keylen;
-               if (mlen == keylen
-                    || (mlen == typebuf.tb_len
-                                 && typebuf.tb_len < keylen))
-               {
-                   char_u  *s;
-                   int     n;
-
-                   // If only script-local mappings are
-                   // allowed, check if the mapping starts
-                   // with K_SNR.
-                   s = typebuf.tb_noremap + typebuf.tb_off;
-                   if (*s == RM_SCRIPT
-                           && (mp->m_keys[0] != K_SPECIAL
-                               || mp->m_keys[1] != KS_EXTRA
-                               || mp->m_keys[2]
-                                             != (int)KE_SNR))
-                       continue;
-
-                   // If one of the typed keys cannot be
-                   // remapped, skip the entry.
-                   for (n = mlen; --n >= 0; )
-                       if (*s++ & (RM_NONE|RM_ABBR))
-                           break;
-                   if (n >= 0)
-                       continue;
-
-                   if (keylen > typebuf.tb_len)
-                   {
-                       if (!*timedout && !(mp_match != NULL
-                                      && mp_match->m_nowait))
-                       {
-                           // break at a partly match
-                           keylen = KEYLEN_PART_MAP;
-                           break;
-                       }
-                   }
-                   else if (keylen > mp_match_len)
-                   {
-                       // found a longer match
-                       mp_match = mp;
-                       mp_match_len = keylen;
-                   }
-               }
-               else
-                   // No match; may have to check for
-                   // termcode at next character.
-                   if (max_mlen < mlen)
-                       max_mlen = mlen;
-           }
-       }
-
-       // If no partly match found, use the longest full
-       // match.
-       if (keylen != KEYLEN_PART_MAP)
-       {
-           mp = mp_match;
-           keylen = mp_match_len;
-       }
-    }
-
-    /*
-     * Check for match with 'pastetoggle'
-     */
-    if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL)))
-    {
-       for (mlen = 0; mlen < typebuf.tb_len && p_pt[mlen];
-                                                      ++mlen)
-           if (p_pt[mlen] != typebuf.tb_buf[typebuf.tb_off
-                                                     + mlen])
-                   break;
-       if (p_pt[mlen] == NUL)  // match
-       {
-           // write chars to script file(s)
-           if (mlen > typebuf.tb_maplen)
-               gotchars(typebuf.tb_buf + typebuf.tb_off
-                                         + typebuf.tb_maplen,
-                                   mlen - typebuf.tb_maplen);
-
-           del_typebuf(mlen, 0); // remove the chars
-           set_option_value((char_u *)"paste",
-                                    (long)!p_paste, NULL, 0);
-           if (!(State & INSERT))
-           {
-               msg_col = 0;
-               msg_row = Rows - 1;
-               msg_clr_eos();          // clear ruler
-           }
-           status_redraw_all();
-           redraw_statuslines();
-           showmode();
-           setcursor();
-           *keylenp = keylen;
-           return map_result_retry;
-       }
-       // Need more chars for partly match.
-       if (mlen == typebuf.tb_len)
-           keylen = KEYLEN_PART_KEY;
-       else if (max_mlen < mlen)
-           // no match, may have to check for termcode at
-           // next character
-           max_mlen = mlen + 1;
-    }
-
-    if ((mp == NULL || max_mlen >= mp_match_len)
-                                && keylen != KEYLEN_PART_MAP)
-    {
-       int     save_keylen = keylen;
-
-       /*
-        * When no matching mapping found or found a
-        * non-matching mapping that matches at least what the
-        * matching mapping matched:
-        * Check if we have a terminal code, when:
-        *  mapping is allowed,
-        *  keys have not been mapped,
-        *  and not an ESC sequence, not in insert mode or
-        *      p_ek is on,
-        *  and when not timed out,
-        */
-       if ((no_mapping == 0 || allow_keys != 0)
-               && (typebuf.tb_maplen == 0
-                   || (p_remap && typebuf.tb_noremap[
-                                  typebuf.tb_off] == RM_YES))
-               && !*timedout)
-       {
-           keylen = check_termcode(max_mlen + 1,
-                                              NULL, 0, NULL);
-
-           // If no termcode matched but 'pastetoggle'
-           // matched partially it's like an incomplete key
-           // sequence.
-           if (keylen == 0 && save_keylen == KEYLEN_PART_KEY)
-               keylen = KEYLEN_PART_KEY;
-
-           // When getting a partial match, but the last
-           // characters were not typed, don't wait for a
-           // typed character to complete the termcode.
-           // This helps a lot when a ":normal" command ends
-           // in an ESC.
-           if (keylen < 0
-                      && typebuf.tb_len == typebuf.tb_maplen)
-               keylen = 0;
-       }
-       else
-           keylen = 0;
-       if (keylen == 0)        // no matching terminal code
-       {
-#ifdef AMIGA                   // check for window bounds report
-           if (typebuf.tb_maplen == 0 && (typebuf.tb_buf[
-                              typebuf.tb_off] & 0xff) == CSI)
-           {
-               char_u *s;
-
-               for (s = typebuf.tb_buf + typebuf.tb_off + 1;
-                       s < typebuf.tb_buf + typebuf.tb_off
-                                             + typebuf.tb_len
-                  && (VIM_ISDIGIT(*s) || *s == ';'
-                                               || *s == ' ');
-                       ++s)
-                   ;
-               if (*s == 'r' || *s == '|') // found one
-               {
-                   del_typebuf((int)(s + 1 -
-                      (typebuf.tb_buf + typebuf.tb_off)), 0);
-                   // get size and redraw screen
-                   shell_resized();
-                   *keylenp = keylen;
-                   return map_result_retry;
-               }
-               if (*s == NUL)      // need more characters
-                   keylen = KEYLEN_PART_KEY;
-           }
-           if (keylen >= 0)
-#endif
-             // When there was a matching mapping and no
-             // termcode could be replaced after another one,
-             // use that mapping (loop around). If there was
-             // no mapping at all use the character from the
-             // typeahead buffer right here.
-             if (mp == NULL)
-             {
-               *keylenp = keylen;
-               return map_result_get;      // got character, break for loop
-             }
-       }
-
-       if (keylen > 0)     // full matching terminal code
-       {
-#if defined(FEAT_GUI) && defined(FEAT_MENU)
-           if (typebuf.tb_len >= 2
-               && typebuf.tb_buf[typebuf.tb_off] == K_SPECIAL
-                        && typebuf.tb_buf[typebuf.tb_off + 1]
-                                                  == KS_MENU)
-           {
-               int     idx;
-
-               // Using a menu may cause a break in undo!
-               // It's like using gotchars(), but without
-               // recording or writing to a script file.
-               may_sync_undo();
-               del_typebuf(3, 0);
-               idx = get_menu_index(current_menu, local_State);
-               if (idx != MENU_INDEX_INVALID)
-               {
-                   // In Select mode and a Visual mode menu
-                   // is used:  Switch to Visual mode
-                   // temporarily.  Append K_SELECT to switch
-                   // back to Select mode.
-                   if (VIsual_active && VIsual_select
-                           && (current_menu->modes & VISUAL))
-                   {
-                       VIsual_select = FALSE;
-                       (void)ins_typebuf(K_SELECT_STRING,
-                                 REMAP_NONE, 0, TRUE, FALSE);
-                   }
-                   ins_typebuf(current_menu->strings[idx],
-                               current_menu->noremap[idx],
-                               0, TRUE,
-                                  current_menu->silent[idx]);
-               }
-           }
-#endif // FEAT_GUI && FEAT_MENU
-           *keylenp = keylen;
-           return map_result_retry;    // try mapping again
-       }
-
-       // Partial match: get some more characters.  When a
-       // matching mapping was found use that one.
-       if (mp == NULL || keylen < 0)
-           keylen = KEYLEN_PART_KEY;
-       else
-           keylen = mp_match_len;
-    }
-
-    /*
-     * complete match
-     */
-    if (keylen >= 0 && keylen <= typebuf.tb_len)
-    {
-       char_u *map_str;
-
-#ifdef FEAT_EVAL
-       int save_m_expr;
-       int save_m_noremap;
-       int save_m_silent;
-       char_u *save_m_keys;
-       char_u *save_m_str;
-#else
-# define save_m_noremap mp->m_noremap
-# define save_m_silent mp->m_silent
-#endif
-
-       // write chars to script file(s)
-       if (keylen > typebuf.tb_maplen)
-           gotchars(typebuf.tb_buf + typebuf.tb_off
-                                         + typebuf.tb_maplen,
-                                 keylen - typebuf.tb_maplen);
-
-       cmd_silent = (typebuf.tb_silent > 0);
-       del_typebuf(keylen, 0); // remove the mapped keys
-
-       /*
-        * Put the replacement string in front of mapstr.
-        * The depth check catches ":map x y" and ":map y x".
-        */
-       if (++*mapdepth >= p_mmd)
-       {
-           emsg(_("E223: recursive mapping"));
-           if (State & CMDLINE)
-               redrawcmdline();
-           else
-               setcursor();
-           flush_buffers(FLUSH_MINIMAL);
-           *mapdepth = 0;      /* for next one */
-           *keylenp = keylen;
-           return map_result_fail;
-       }
-
-       /*
-        * In Select mode and a Visual mode mapping is used:
-        * Switch to Visual mode temporarily.  Append K_SELECT
-        * to switch back to Select mode.
-        */
-       if (VIsual_active && VIsual_select
-                                    && (mp->m_mode & VISUAL))
-       {
-           VIsual_select = FALSE;
-           (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE,
-                                             0, TRUE, FALSE);
-       }
-
-#ifdef FEAT_EVAL
-       // Copy the values from *mp that are used, because
-       // evaluating the expression may invoke a function
-       // that redefines the mapping, thereby making *mp
-       // invalid.
-       save_m_expr = mp->m_expr;
-       save_m_noremap = mp->m_noremap;
-       save_m_silent = mp->m_silent;
-       save_m_keys = NULL;  // only saved when needed
-       save_m_str = NULL;  // only saved when needed
-
-       /*
-        * Handle ":map <expr>": evaluate the {rhs} as an
-        * expression.  Also save and restore the command line
-        * for "normal :".
-        */
-       if (mp->m_expr)
-       {
-           int save_vgetc_busy = vgetc_busy;
-           int save_may_garbage_collect = may_garbage_collect;
-
-           vgetc_busy = 0;
-           may_garbage_collect = FALSE;
-
-           save_m_keys = vim_strsave(mp->m_keys);
-           save_m_str = vim_strsave(mp->m_str);
-           map_str = eval_map_expr(save_m_str, NUL);
-
-           vgetc_busy = save_vgetc_busy;
-           may_garbage_collect = save_may_garbage_collect;
-       }
-       else
-#endif
-           map_str = mp->m_str;
-
-       /*
-        * Insert the 'to' part in the typebuf.tb_buf.
-        * If 'from' field is the same as the start of the
-        * 'to' field, don't remap the first character (but do
-        * allow abbreviations).
-        * If m_noremap is set, don't remap the whole 'to'
-        * part.
-        */
-       if (map_str == NULL)
-           i = FAIL;
-       else
-       {
-           int noremap;
-
-           if (save_m_noremap != REMAP_YES)
-               noremap = save_m_noremap;
-           else if (
-#ifdef FEAT_EVAL
-               STRNCMP(map_str, save_m_keys != NULL
-                                  ? save_m_keys : mp->m_keys,
-                                        (size_t)keylen)
-#else
-               STRNCMP(map_str, mp->m_keys, (size_t)keylen)
-#endif
-                  != 0)
-               noremap = REMAP_YES;
-           else
-               noremap = REMAP_SKIP;
-           i = ins_typebuf(map_str, noremap,
-                                        0, TRUE, cmd_silent || save_m_silent);
-#ifdef FEAT_EVAL
-           if (save_m_expr)
-               vim_free(map_str);
-#endif
-       }
-#ifdef FEAT_EVAL
-       vim_free(save_m_keys);
-       vim_free(save_m_str);
-#endif
-       *keylenp = keylen;
-       if (i == FAIL)
-           return map_result_fail;
-       return map_result_retry;
-    }
-
-    *keylenp = keylen;
-    return map_result_nomatch;
-}
-
 /*
  * unget one character (can only be done once!)
  */
@@ -2466,18 +1942,33 @@ vungetc(int c)
 vgetorpeek(int advance)
 {
     int                c, c1;
+    int                keylen;
+    char_u     *s;
+    mapblock_T *mp;
+    mapblock_T *mp2;
+    mapblock_T *mp_match;
+    int                mp_match_len = 0;
     int                timedout = FALSE;           /* waited for more than 1 second
                                                for mapping to complete */
     int                mapdepth = 0;       /* check for recursive mapping */
     int                mode_deleted = FALSE;   /* set when mode has been deleted */
+    int                local_State;
+    int                mlen;
+    int                max_mlen;
     int                i;
 #ifdef FEAT_CMDL_INFO
     int                new_wcol, new_wrow;
 #endif
 #ifdef FEAT_GUI
+# ifdef FEAT_MENU
+    int                idx;
+# endif
     int                shape_changed = FALSE;  /* adjusted cursor shape */
 #endif
     int                n;
+#ifdef FEAT_LANGMAP
+    int                nolmaplen;
+#endif
     int                old_wcol, old_wrow;
     int                wait_tb_len;
 
@@ -2495,6 +1986,8 @@ vgetorpeek(int advance)
     if (vgetc_busy > 0 && ex_normal_busy == 0)
        return NUL;
 
+    local_State = get_real_state();
+
     ++vgetc_busy;
 
     if (advance)
@@ -2539,8 +2032,7 @@ vgetorpeek(int advance)
             */
            for (;;)
            {
-               long    wait_time;
-               int     keylen = 0;
+               long        wait_time;
 
                /*
                 * ui_breakcheck() is slow, don't use it too often when
@@ -2551,11 +2043,11 @@ vgetorpeek(int advance)
                    line_breakcheck();
                else
                    ui_breakcheck();            /* check for CTRL-C */
+               keylen = 0;
                if (got_int)
                {
                    /* flush all input */
                    c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L);
-
                    /*
                     * If inchar() returns TRUE (script file was active) or we
                     * are inside a mapping, get out of Insert mode.
@@ -2584,46 +2076,508 @@ vgetorpeek(int advance)
                else if (typebuf.tb_len > 0)
                {
                    /*
-                    * Check for a mapping in "typebuf".
+                    * Check for a mappable key sequence.
+                    * Walk through one maphash[] list until we find an
+                    * entry that matches.
+                    *
+                    * Don't look for mappings if:
+                    * - no_mapping set: mapping disabled (e.g. for CTRL-V)
+                    * - maphash_valid not set: no mappings present.
+                    * - typebuf.tb_buf[typebuf.tb_off] should not be remapped
+                    * - in insert or cmdline mode and 'paste' option set
+                    * - waiting for "hit return to continue" and CR or SPACE
+                    *   typed
+                    * - waiting for a char with --more--
+                    * - in Ctrl-X mode, and we get a valid char for that mode
                     */
-                   map_result_T result = handle_mapping(
-                                               &keylen, &timedout, &mapdepth);
+                   mp = NULL;
+                   max_mlen = 0;
+                   c1 = typebuf.tb_buf[typebuf.tb_off];
+                   if (no_mapping == 0 && is_maphash_valid()
+                           && (no_zero_mapping == 0 || c1 != '0')
+                           && (typebuf.tb_maplen == 0
+                               || (p_remap
+                                   && (typebuf.tb_noremap[typebuf.tb_off]
+                                                   & (RM_NONE|RM_ABBR)) == 0))
+                           && !(p_paste && (State & (INSERT + CMDLINE)))
+                           && !(State == HITRETURN && (c1 == CAR || c1 == ' '))
+                           && State != ASKMORE
+                           && State != CONFIRM
+#ifdef FEAT_INS_EXPAND
+                           && !((ctrl_x_mode_not_default()
+                                                     && vim_is_ctrl_x_key(c1))
+                                   || ((compl_cont_status & CONT_LOCAL)
+                                       && (c1 == Ctrl_N || c1 == Ctrl_P)))
+#endif
+                           )
+                   {
+#ifdef FEAT_LANGMAP
+                       if (c1 == K_SPECIAL)
+                           nolmaplen = 2;
+                       else
+                       {
+                           LANGMAP_ADJUST(c1,
+                                          (State & (CMDLINE | INSERT)) == 0
+                                          && get_real_state() != SELECTMODE);
+                           nolmaplen = 0;
+                       }
+#endif
+                       // First try buffer-local mappings.
+                       mp = get_buf_maphash_list(local_State, c1);
+                       mp2 = get_maphash_list(local_State, c1);
+                       if (mp == NULL)
+                       {
+                           // There are no buffer-local mappings.
+                           mp = mp2;
+                           mp2 = NULL;
+                       }
+                       /*
+                        * Loop until a partly matching mapping is found or
+                        * all (local) mappings have been checked.
+                        * The longest full match is remembered in "mp_match".
+                        * A full match is only accepted if there is no partly
+                        * match, so "aa" and "aaa" can both be mapped.
+                        */
+                       mp_match = NULL;
+                       mp_match_len = 0;
+                       for ( ; mp != NULL;
+                               mp->m_next == NULL ? (mp = mp2, mp2 = NULL)
+                                                  : (mp = mp->m_next))
+                       {
+                           /*
+                            * Only consider an entry if the first character
+                            * matches and it is for the current state.
+                            * Skip ":lmap" mappings if keys were mapped.
+                            */
+                           if (mp->m_keys[0] == c1
+                                   && (mp->m_mode & local_State)
+                                   && ((mp->m_mode & LANGMAP) == 0
+                                       || typebuf.tb_maplen == 0))
+                           {
+#ifdef FEAT_LANGMAP
+                               int     nomap = nolmaplen;
+                               int     c2;
+#endif
+                               /* find the match length of this mapping */
+                               for (mlen = 1; mlen < typebuf.tb_len; ++mlen)
+                               {
+#ifdef FEAT_LANGMAP
+                                   c2 = typebuf.tb_buf[typebuf.tb_off + mlen];
+                                   if (nomap > 0)
+                                       --nomap;
+                                   else if (c2 == K_SPECIAL)
+                                       nomap = 2;
+                                   else
+                                       LANGMAP_ADJUST(c2, TRUE);
+                                   if (mp->m_keys[mlen] != c2)
+#else
+                                   if (mp->m_keys[mlen] !=
+                                       typebuf.tb_buf[typebuf.tb_off + mlen])
+#endif
+                                       break;
+                               }
 
-                   if (result == map_result_retry)
-                       // try mapping again
-                       continue;
-                   if (result == map_result_fail)
+                               /* Don't allow mapping the first byte(s) of a
+                                * multi-byte char.  Happens when mapping
+                                * <M-a> and then changing 'encoding'. Beware
+                                * that 0x80 is escaped. */
+                               {
+                                   char_u *p1 = mp->m_keys;
+                                   char_u *p2 = mb_unescape(&p1);
+
+                                   if (has_mbyte && p2 != NULL
+                                         && MB_BYTE2LEN(c1) > MB_PTR2LEN(p2))
+                                       mlen = 0;
+                               }
+                               /*
+                                * Check an entry whether it matches.
+                                * - Full match: mlen == keylen
+                                * - Partly match: mlen == typebuf.tb_len
+                                */
+                               keylen = mp->m_keylen;
+                               if (mlen == keylen
+                                    || (mlen == typebuf.tb_len
+                                                 && typebuf.tb_len < keylen))
+                               {
+                                   /*
+                                    * If only script-local mappings are
+                                    * allowed, check if the mapping starts
+                                    * with K_SNR.
+                                    */
+                                   s = typebuf.tb_noremap + typebuf.tb_off;
+                                   if (*s == RM_SCRIPT
+                                           && (mp->m_keys[0] != K_SPECIAL
+                                               || mp->m_keys[1] != KS_EXTRA
+                                               || mp->m_keys[2]
+                                                             != (int)KE_SNR))
+                                       continue;
+                                   /*
+                                    * If one of the typed keys cannot be
+                                    * remapped, skip the entry.
+                                    */
+                                   for (n = mlen; --n >= 0; )
+                                       if (*s++ & (RM_NONE|RM_ABBR))
+                                           break;
+                                   if (n >= 0)
+                                       continue;
+
+                                   if (keylen > typebuf.tb_len)
+                                   {
+                                       if (!timedout && !(mp_match != NULL
+                                                      && mp_match->m_nowait))
+                                       {
+                                           /* break at a partly match */
+                                           keylen = KEYLEN_PART_MAP;
+                                           break;
+                                       }
+                                   }
+                                   else if (keylen > mp_match_len)
+                                   {
+                                       /* found a longer match */
+                                       mp_match = mp;
+                                       mp_match_len = keylen;
+                                   }
+                               }
+                               else
+                                   /* No match; may have to check for
+                                    * termcode at next character. */
+                                   if (max_mlen < mlen)
+                                       max_mlen = mlen;
+                           }
+                       }
+
+                       /* If no partly match found, use the longest full
+                        * match. */
+                       if (keylen != KEYLEN_PART_MAP)
+                       {
+                           mp = mp_match;
+                           keylen = mp_match_len;
+                       }
+                   }
+
+                   /* Check for match with 'pastetoggle' */
+                   if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL)))
                    {
-                       // failed, use the outer loop
-                       c = -1;
-                       break;
+                       for (mlen = 0; mlen < typebuf.tb_len && p_pt[mlen];
+                                                                      ++mlen)
+                           if (p_pt[mlen] != typebuf.tb_buf[typebuf.tb_off
+                                                                     + mlen])
+                                   break;
+                       if (p_pt[mlen] == NUL)  /* match */
+                       {
+                           /* write chars to script file(s) */
+                           if (mlen > typebuf.tb_maplen)
+                               gotchars(typebuf.tb_buf + typebuf.tb_off
+                                                         + typebuf.tb_maplen,
+                                                   mlen - typebuf.tb_maplen);
+
+                           del_typebuf(mlen, 0); /* remove the chars */
+                           set_option_value((char_u *)"paste",
+                                                    (long)!p_paste, NULL, 0);
+                           if (!(State & INSERT))
+                           {
+                               msg_col = 0;
+                               msg_row = Rows - 1;
+                               msg_clr_eos();          /* clear ruler */
+                           }
+                           status_redraw_all();
+                           redraw_statuslines();
+                           showmode();
+                           setcursor();
+                           continue;
+                       }
+                       /* Need more chars for partly match. */
+                       if (mlen == typebuf.tb_len)
+                           keylen = KEYLEN_PART_KEY;
+                       else if (max_mlen < mlen)
+                           /* no match, may have to check for termcode at
+                            * next character */
+                           max_mlen = mlen + 1;
                    }
-                   if (result == map_result_get)
+
+                   if ((mp == NULL || max_mlen >= mp_match_len)
+                                                && keylen != KEYLEN_PART_MAP)
                    {
+                       int     save_keylen = keylen;
+
+                       /*
+                        * When no matching mapping found or found a
+                        * non-matching mapping that matches at least what the
+                        * matching mapping matched:
+                        * Check if we have a terminal code, when:
+                        *  mapping is allowed,
+                        *  keys have not been mapped,
+                        *  and not an ESC sequence, not in insert mode or
+                        *      p_ek is on,
+                        *  and when not timed out,
+                        */
+                       if ((no_mapping == 0 || allow_keys != 0)
+                               && (typebuf.tb_maplen == 0
+                                   || (p_remap && typebuf.tb_noremap[
+                                                  typebuf.tb_off] == RM_YES))
+                               && !timedout)
+                       {
+                           keylen = check_termcode(max_mlen + 1,
+                                                              NULL, 0, NULL);
+
+                           /* If no termcode matched but 'pastetoggle'
+                            * matched partially it's like an incomplete key
+                            * sequence. */
+                           if (keylen == 0 && save_keylen == KEYLEN_PART_KEY)
+                               keylen = KEYLEN_PART_KEY;
+
+                           /*
+                            * When getting a partial match, but the last
+                            * characters were not typed, don't wait for a
+                            * typed character to complete the termcode.
+                            * This helps a lot when a ":normal" command ends
+                            * in an ESC.
+                            */
+                           if (keylen < 0
+                                      && typebuf.tb_len == typebuf.tb_maplen)
+                               keylen = 0;
+                       }
+                       else
+                           keylen = 0;
+                       if (keylen == 0)        /* no matching terminal code */
+                       {
+#ifdef AMIGA                   /* check for window bounds report */
+                           if (typebuf.tb_maplen == 0 && (typebuf.tb_buf[
+                                              typebuf.tb_off] & 0xff) == CSI)
+                           {
+                               for (s = typebuf.tb_buf + typebuf.tb_off + 1;
+                                       s < typebuf.tb_buf + typebuf.tb_off
+                                                             + typebuf.tb_len
+                                  && (VIM_ISDIGIT(*s) || *s == ';'
+                                                               || *s == ' ');
+                                       ++s)
+                                   ;
+                               if (*s == 'r' || *s == '|') /* found one */
+                               {
+                                   del_typebuf((int)(s + 1 -
+                                      (typebuf.tb_buf + typebuf.tb_off)), 0);
+                                   /* get size and redraw screen */
+                                   shell_resized();
+                                   continue;
+                               }
+                               if (*s == NUL)      /* need more characters */
+                                   keylen = KEYLEN_PART_KEY;
+                           }
+                           if (keylen >= 0)
+#endif
+                             /* When there was a matching mapping and no
+                              * termcode could be replaced after another one,
+                              * use that mapping (loop around). If there was
+                              * no mapping use the character from the
+                              * typeahead buffer right here. */
+                             if (mp == NULL)
+                             {
 /*
  * get a character: 2. from the typeahead buffer
  */
-                       c = typebuf.tb_buf[typebuf.tb_off] & 255;
-                       if (advance)    /* remove chars from tb_buf */
+                               c = typebuf.tb_buf[typebuf.tb_off] & 255;
+                               if (advance)    /* remove chars from tb_buf */
+                               {
+                                   cmd_silent = (typebuf.tb_silent > 0);
+                                   if (typebuf.tb_maplen > 0)
+                                       KeyTyped = FALSE;
+                                   else
+                                   {
+                                       KeyTyped = TRUE;
+                                       /* write char to script file(s) */
+                                       gotchars(typebuf.tb_buf
+                                                        + typebuf.tb_off, 1);
+                                   }
+                                   KeyNoremap = typebuf.tb_noremap[
+                                                             typebuf.tb_off];
+                                   del_typebuf(1, 0);
+                               }
+                               break;      /* got character, break for loop */
+                             }
+                       }
+                       if (keylen > 0)     /* full matching terminal code */
                        {
-                           cmd_silent = (typebuf.tb_silent > 0);
-                           if (typebuf.tb_maplen > 0)
-                               KeyTyped = FALSE;
-                           else
+#if defined(FEAT_GUI) && defined(FEAT_MENU)
+                           if (typebuf.tb_len >= 2
+                               && typebuf.tb_buf[typebuf.tb_off] == K_SPECIAL
+                                        && typebuf.tb_buf[typebuf.tb_off + 1]
+                                                                  == KS_MENU)
                            {
-                               KeyTyped = TRUE;
-                               /* write char to script file(s) */
-                               gotchars(typebuf.tb_buf
-                                                + typebuf.tb_off, 1);
+                               /*
+                                * Using a menu may cause a break in undo!
+                                * It's like using gotchars(), but without
+                                * recording or writing to a script file.
+                                */
+                               may_sync_undo();
+                               del_typebuf(3, 0);
+                               idx = get_menu_index(current_menu, local_State);
+                               if (idx != MENU_INDEX_INVALID)
+                               {
+                                   /*
+                                    * In Select mode and a Visual mode menu
+                                    * is used:  Switch to Visual mode
+                                    * temporarily.  Append K_SELECT to switch
+                                    * back to Select mode.
+                                    */
+                                   if (VIsual_active && VIsual_select
+                                           && (current_menu->modes & VISUAL))
+                                   {
+                                       VIsual_select = FALSE;
+                                       (void)ins_typebuf(K_SELECT_STRING,
+                                                 REMAP_NONE, 0, TRUE, FALSE);
+                                   }
+                                   ins_typebuf(current_menu->strings[idx],
+                                               current_menu->noremap[idx],
+                                               0, TRUE,
+                                                  current_menu->silent[idx]);
+                               }
                            }
-                           KeyNoremap = typebuf.tb_noremap[
-                                                     typebuf.tb_off];
-                           del_typebuf(1, 0);
+#endif /* FEAT_GUI && FEAT_MENU */
+                           continue;   /* try mapping again */
                        }
-                       break;
+
+                       /* Partial match: get some more characters.  When a
+                        * matching mapping was found use that one. */
+                       if (mp == NULL || keylen < 0)
+                           keylen = KEYLEN_PART_KEY;
+                       else
+                           keylen = mp_match_len;
                    }
 
-                   // not enough characters, get more
+                   /* complete match */
+                   if (keylen >= 0 && keylen <= typebuf.tb_len)
+                   {
+#ifdef FEAT_EVAL
+                       int save_m_expr;
+                       int save_m_noremap;
+                       int save_m_silent;
+                       char_u *save_m_keys;
+                       char_u *save_m_str;
+#else
+# define save_m_noremap mp->m_noremap
+# define save_m_silent mp->m_silent
+#endif
+
+                       /* write chars to script file(s) */
+                       if (keylen > typebuf.tb_maplen)
+                           gotchars(typebuf.tb_buf + typebuf.tb_off
+                                                         + typebuf.tb_maplen,
+                                                 keylen - typebuf.tb_maplen);
+
+                       cmd_silent = (typebuf.tb_silent > 0);
+                       del_typebuf(keylen, 0); /* remove the mapped keys */
+
+                       /*
+                        * Put the replacement string in front of mapstr.
+                        * The depth check catches ":map x y" and ":map y x".
+                        */
+                       if (++mapdepth >= p_mmd)
+                       {
+                           emsg(_("E223: recursive mapping"));
+                           if (State & CMDLINE)
+                               redrawcmdline();
+                           else
+                               setcursor();
+                           flush_buffers(FLUSH_MINIMAL);
+                           mapdepth = 0;       /* for next one */
+                           c = -1;
+                           break;
+                       }
+
+                       /*
+                        * In Select mode and a Visual mode mapping is used:
+                        * Switch to Visual mode temporarily.  Append K_SELECT
+                        * to switch back to Select mode.
+                        */
+                       if (VIsual_active && VIsual_select
+                                                    && (mp->m_mode & VISUAL))
+                       {
+                           VIsual_select = FALSE;
+                           (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE,
+                                                             0, TRUE, FALSE);
+                       }
+
+#ifdef FEAT_EVAL
+                       /* Copy the values from *mp that are used, because
+                        * evaluating the expression may invoke a function
+                        * that redefines the mapping, thereby making *mp
+                        * invalid. */
+                       save_m_expr = mp->m_expr;
+                       save_m_noremap = mp->m_noremap;
+                       save_m_silent = mp->m_silent;
+                       save_m_keys = NULL;  /* only saved when needed */
+                       save_m_str = NULL;  /* only saved when needed */
+
+                       /*
+                        * Handle ":map <expr>": evaluate the {rhs} as an
+                        * expression.  Also save and restore the command line
+                        * for "normal :".
+                        */
+                       if (mp->m_expr)
+                       {
+                           int save_vgetc_busy = vgetc_busy;
+                           int save_may_garbage_collect = may_garbage_collect;
+
+                           vgetc_busy = 0;
+                           may_garbage_collect = FALSE;
+
+                           save_m_keys = vim_strsave(mp->m_keys);
+                           save_m_str = vim_strsave(mp->m_str);
+                           s = eval_map_expr(save_m_str, NUL);
+
+                           vgetc_busy = save_vgetc_busy;
+                           may_garbage_collect = save_may_garbage_collect;
+                       }
+                       else
+#endif
+                           s = mp->m_str;
+
+                       /*
+                        * Insert the 'to' part in the typebuf.tb_buf.
+                        * If 'from' field is the same as the start of the
+                        * 'to' field, don't remap the first character (but do
+                        * allow abbreviations).
+                        * If m_noremap is set, don't remap the whole 'to'
+                        * part.
+                        */
+                       if (s == NULL)
+                           i = FAIL;
+                       else
+                       {
+                           int noremap;
+
+                           if (save_m_noremap != REMAP_YES)
+                               noremap = save_m_noremap;
+                           else if (
+#ifdef FEAT_EVAL
+                               STRNCMP(s, save_m_keys != NULL
+                                                  ? save_m_keys : mp->m_keys,
+                                                        (size_t)keylen)
+#else
+                               STRNCMP(s, mp->m_keys, (size_t)keylen)
+#endif
+                                  != 0)
+                               noremap = REMAP_YES;
+                           else
+                               noremap = REMAP_SKIP;
+                           i = ins_typebuf(s, noremap,
+                                       0, TRUE, cmd_silent || save_m_silent);
+#ifdef FEAT_EVAL
+                           if (save_m_expr)
+                               vim_free(s);
+#endif
+                       }
+#ifdef FEAT_EVAL
+                       vim_free(save_m_keys);
+                       vim_free(save_m_str);
+#endif
+                       if (i == FAIL)
+                       {
+                           c = -1;
+                           break;
+                       }
+                       continue;
+                   }
                }
 
 /*
index 653ed8305ba1eaaefe8e2b8f1188826dfd94b390..43999bf664d75380167507c219f5790df294c79a 100644 (file)
@@ -773,6 +773,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1794,
 /**/
     1793,
 /**/