Patch 8.1.1797 (after 8.1.1794)
Problem: The vgetorpeek() function is too long.
Solution: Split off the part that handles mappings, with fix.
Files: src/getchar.c
*** ../vim-8.1.1796/src/getchar.c 2019-08-02 22:46:08.317622692 +0200
--- src/getchar.c 2019-08-03 14:08:35.974397757 +0200
***************
*** 1900,1905 ****
--- 1900,2429 ----
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,1974 ****
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;
--- 2466,2483 ----
***************
*** 1986,1993 ****
if (vgetc_busy > 0 && ex_normal_busy == 0)
return NUL;
- local_State = get_real_state();
-
++vgetc_busy;
if (advance)
--- 2495,2500 ----
***************
*** 2032,2038 ****
*/
for (;;)
{
! long wait_time;
/*
* ui_breakcheck() is slow, don't use it too often when
--- 2539,2546 ----
*/
for (;;)
{
! long wait_time;
! int keylen = 0;
/*
* ui_breakcheck() is slow, don't use it too often when
***************
*** 2043,2053 ****
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.
--- 2551,2561 ----
line_breakcheck();
else
ui_breakcheck(); /* check for CTRL-C */
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,2583 ****
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
*/
! 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);
!
! 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)))
{
! 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 ((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 */
! {
! 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 */
{
! #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)
{
! /*
! * 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 */
! continue; /* 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)
! {
! #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;
! }
}
/*
--- 2584,2629 ----
else if (typebuf.tb_len > 0)
{
/*
! * Check for a mapping in "typebuf".
*/
! map_result_T result = handle_mapping(
! &keylen, &timedout, &mapdepth);
! if (result == map_result_retry)
! // try mapping again
! continue;
! if (result == map_result_fail)
{
! // failed, use the outer loop
! c = -1;
! break;
}
! if (result == map_result_get)
{
/*
* 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;
}
! // not enough characters, get more
}
/*
*** ../vim-8.1.1796/src/version.c 2019-08-03 13:50:04.562299913 +0200
--- src/version.c 2019-08-03 14:23:10.987633555 +0200
***************
*** 775,776 ****
--- 775,778 ----
{ /* Add new patch number below this line */
+ /**/
+ 1797,
/**/
--
hundred-and-one symptoms of being an internet addict:
15. Your heart races faster and beats irregularly each time you see a new WWW
site address in print or on TV, even though you've never had heart
problems before.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///