To: vim_dev@googlegroups.com Subject: Patch 8.1.1797 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 + // 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,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 ! * 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 ": 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 -- Bram@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 ///