]> granicus.if.org Git - vim/commitdiff
patch 8.1.1797: the vgetorpeek() function is too long v8.1.1797
authorBram Moolenaar <Bram@vim.org>
Sat, 3 Aug 2019 12:23:48 +0000 (14:23 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 3 Aug 2019 12:23:48 +0000 (14:23 +0200)
Problem:    The vgetorpeek() function is too long.
Solution:   Split off the part that handles mappings, with fix.

src/getchar.c
src/version.c

index 8c1a01a3e4f003c9871a53df684a41074214bc9b..0c1d4e8f6f83e5fa72613c53d57d28efd4552154 100644 (file)
@@ -1900,6 +1900,530 @@ 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 = *keylenp;
+    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!)
  */
@@ -1942,33 +2466,18 @@ 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;
 
@@ -1986,8 +2495,6 @@ vgetorpeek(int advance)
     if (vgetc_busy > 0 && ex_normal_busy == 0)
        return NUL;
 
-    local_State = get_real_state();
-
     ++vgetc_busy;
 
     if (advance)
@@ -2032,7 +2539,8 @@ vgetorpeek(int advance)
             */
            for (;;)
            {
-               long        wait_time;
+               long    wait_time;
+               int     keylen = 0;
 
                /*
                 * ui_breakcheck() is slow, don't use it too often when
@@ -2043,11 +2551,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.
@@ -2076,508 +2584,46 @@ vgetorpeek(int advance)
                else if (typebuf.tb_len > 0)
                {
                    /*
-                    * 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
+                    * Check for a mapping in "typebuf".
                     */
-                   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;
-                               }
-
-                               /* 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);
+                   map_result_T result = handle_mapping(
+                                               &keylen, &timedout, &mapdepth);
 
-                                   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)))
+                   if (result == map_result_retry)
+                       // try mapping again
+                       continue;
+                   if (result == map_result_fail)
                    {
-                       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;
+                       // failed, use the outer loop
+                       c = -1;
+                       break;
                    }
-
-                   if ((mp == NULL || max_mlen >= mp_match_len)
-                                                && keylen != KEYLEN_PART_MAP)
+                   if (result == map_result_get)
                    {
-                       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 */
-                               {
-                                   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 */
+                       c = typebuf.tb_buf[typebuf.tb_off] & 255;
+                       if (advance)    /* remove chars from tb_buf */
                        {
-#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)
+                           cmd_silent = (typebuf.tb_silent > 0);
+                           if (typebuf.tb_maplen > 0)
+                               KeyTyped = FALSE;
+                           else
                            {
-                               /*
-                                * 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]);
-                               }
+                               KeyTyped = TRUE;
+                               /* write char to script file(s) */
+                               gotchars(typebuf.tb_buf
+                                                + typebuf.tb_off, 1);
                            }
-#endif /* FEAT_GUI && FEAT_MENU */
-                           continue;   /* try mapping again */
+                           KeyNoremap = typebuf.tb_noremap[
+                                                     typebuf.tb_off];
+                           del_typebuf(1, 0);
                        }
-
-                       /* 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;
+                       break;
                    }
 
-                   /* 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;
-                   }
+                   // not enough characters, get more
                }
 
 /*
index 2b9149095f775a009197d11be82059b488ca3f2f..c3af73a5445869d766845ffdb3b092caa0442df3 100644 (file)
@@ -773,6 +773,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1797,
 /**/
     1796,
 /**/