# HG changeset patch # User Bram Moolenaar # Date 1564835405 -7200 # Node ID ca42eb7894725fda192262dc73b90763b7f3f646 # Parent c4e9b24b4834112a264976755606fd1723fb7bb8 patch 8.1.1797: the vgetorpeek() function is too long commit https://github.com/vim/vim/commit/edd680f3649c47d7ed5818e356e7c47f874f5cf8 Author: Bram Moolenaar Date: Sat Aug 3 14:23:48 2019 +0200 patch 8.1.1797: the vgetorpeek() function is too long Problem: The vgetorpeek() function is too long. Solution: Split off the part that handles mappings, with fix. diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -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 + // 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 ": 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 - * 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; + map_result_T result = handle_mapping( + &keylen, &timedout, &mapdepth); - 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 ": 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 } /* diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -774,6 +774,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1797, +/**/ 1796, /**/ 1795,