aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/getchar.c843
1 files changed, 407 insertions, 436 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index bc3cbaa986..27e8cb36af 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1680,6 +1680,325 @@ int 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, bool *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;
+ int nolmaplen;
+ 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 && 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))))
+ && !(p_paste && (State & (INSERT + CMDLINE)))
+ && !(State == HITRETURN && (tb_c1 == CAR || tb_c1 == ' '))
+ && State != ASKMORE
+ && State != CONFIRM
+ && !((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)))) {
+ if (tb_c1 == K_SPECIAL) {
+ nolmaplen = 2;
+ } else {
+ LANGMAP_ADJUST(tb_c1, !(State & (CMDLINE | INSERT)) && get_real_state() != SELECTMODE);
+ nolmaplen = 0;
+ }
+ // First try buffer-local mappings.
+ mp = curbuf->b_maphash[MAP_HASH(local_State, tb_c1)];
+ mp2 = maphash[MAP_HASH(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)) {
+ int nomap = nolmaplen;
+ int c2;
+ // find the match length of this mapping
+ for (mlen = 1; mlen < typebuf.tb_len; mlen++) {
+ 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) {
+ 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 = (char_u *)mb_unescape((const char **)&p1);
+
+ if (p2 != NULL && MB_BYTE2LEN(tb_c1) > utfc_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] != 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
+ || (keylen == mp_match_len
+ && mp_match != NULL
+ && (mp_match->m_mode & LANGMAP) == 0
+ && (mp->m_mode & LANGMAP) != 0)) {
+ // 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))) {
+ bool match = typebuf_match_len(p_pt, &mlen);
+ if (match) {
+ // write chars to script file(s)
+ if (mlen > typebuf.tb_maplen) {
+ gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
+ (size_t)(mlen - typebuf.tb_maplen));
+ }
+
+ del_typebuf(mlen, 0); // remove the chars
+ set_option_value("paste", !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) {
+ // No matching mapping found or found a non-matching mapping that
+ // matches at least what the matching mapping matched
+ keylen = 0;
+ (void)keylen; // suppress clang/dead assignment
+ // If there was no mapping, use the character from the typeahead
+ // buffer right here. Otherwise, use the mapping (loop around).
+ if (mp == NULL) {
+ *keylenp = keylen;
+ return map_result_get; // got character, break for loop
+ } else {
+ keylen = mp_match_len;
+ }
+ }
+
+ // complete match
+ if (keylen >= 0 && keylen <= typebuf.tb_len) {
+ char_u *map_str;
+ int save_m_expr;
+ int save_m_noremap;
+ int save_m_silent;
+
+ // Write chars to script file(s).
+ // Note: :lmap mappings are written *after* being applied. #5658
+ if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) == 0) {
+ gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
+ (size_t)(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);
+ }
+
+ // 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;
+ char_u *save_m_keys = NULL; // only saved when needed
+ char_u *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;
+ const bool 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 {
+ 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 this is a LANGMAP mapping, then we didn't record the keys
+ // at the start of the function and have to record them now.
+ if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) != 0) {
+ gotchars(map_str, STRLEN(map_str));
+ }
+
+ if (save_m_noremap != REMAP_YES) {
+ noremap = save_m_noremap;
+ } else if (STRNCMP(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys,
+ (size_t)keylen) != 0) {
+ noremap = REMAP_YES;
+ } else {
+ noremap = REMAP_SKIP;
+ }
+ i = ins_typebuf(map_str, noremap, 0, true, cmd_silent || save_m_silent);
+ if (save_m_expr) {
+ xfree(map_str);
+ }
+ }
+ xfree(save_m_keys);
+ xfree(save_m_str);
+ *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!)
void vungetc(int c)
{
@@ -1715,44 +2034,27 @@ void vungetc(int c)
static int vgetorpeek(bool advance)
{
int c, c1;
- int keylen;
- char_u *s;
- mapblock_T *mp;
- mapblock_T *mp2;
- mapblock_T *mp_match;
- int mp_match_len = 0;
- bool timedout = false; // waited for more than 1 second
- // for mapping to complete
+ bool timedout = false; // waited for more than 1 second for mapping to complete
int mapdepth = 0; // check for recursive mapping
bool mode_deleted = false; // set when mode has been deleted
- int local_State;
- int mlen;
- int max_mlen;
- int i;
int new_wcol, new_wrow;
int n;
- int nolmaplen;
int old_wcol, old_wrow;
int wait_tb_len;
- /*
- * This function doesn't work very well when called recursively. This may
- * happen though, because of:
- * 1. The call to add_to_showcmd(). char_avail() is then used to check if
- * there is a character available, which calls this function. In that
- * case we must return NUL, to indicate no character is available.
- * 2. A GUI callback function writes to the screen, causing a
- * wait_return().
- * Using ":normal" can also do this, but it saves the typeahead buffer,
- * thus it should be OK. But don't get a key from the user then.
- */
- if (vgetc_busy > 0
- && ex_normal_busy == 0) {
+ // This function doesn't work very well when called recursively. This may
+ // happen though, because of:
+ // 1. The call to add_to_showcmd(). char_avail() is then used to check if
+ // there is a character available, which calls this function. In that
+ // case we must return NUL, to indicate no character is available.
+ // 2. A GUI callback function writes to the screen, causing a
+ // wait_return().
+ // Using ":normal" can also do this, but it saves the typeahead buffer,
+ // thus it should be OK. But don't get a key from the user then.
+ if (vgetc_busy > 0 && ex_normal_busy == 0) {
return NUL;
}
- local_State = get_real_state();
-
++vgetc_busy;
if (advance) {
@@ -1765,9 +2067,7 @@ static int vgetorpeek(bool advance)
reg_executing = 0;
}
do {
- /*
- * get a character: 1. from the stuffbuffer
- */
+ // get a character: 1. from the stuffbuffer
if (typeahead_char != 0) {
c = typeahead_char;
if (advance) {
@@ -1784,15 +2084,13 @@ static int vgetorpeek(bool advance)
KeyStuffed = true;
}
if (typebuf.tb_no_abbr_cnt == 0) {
- typebuf.tb_no_abbr_cnt = 1; // no abbreviations now
+ typebuf.tb_no_abbr_cnt = 1; // no abbreviations now
}
} else {
- /*
- * Loop until we either find a matching mapped key, or we
- * are sure that it is not a mapped key.
- * If a mapped key sequence is found we go back to the start to
- * try re-mapping.
- */
+ // Loop until we either find a matching mapped key, or we
+ // are sure that it is not a mapped key.
+ // If a mapped key sequence is found we go back to the start to
+ // try re-mapping.
for (;;) {
// os_breakcheck() is slow, don't use it too often when
// inside a mapping. But call it each time for typed
@@ -1800,12 +2098,13 @@ static int vgetorpeek(bool advance)
if (typebuf.tb_maplen) {
line_breakcheck();
} else {
- os_breakcheck(); // check for CTRL-C
+ os_breakcheck(); // check for CTRL-C
}
- keylen = 0;
+ int 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.
// Otherwise we behave like having gotten a CTRL-C.
@@ -1829,361 +2128,49 @@ static int vgetorpeek(bool advance)
break;
} 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 && 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
- && !((ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c1))
- || ((compl_cont_status & CONT_LOCAL)
- && (c1 == Ctrl_N
- || c1 == Ctrl_P)))) {
- if (c1 == K_SPECIAL) {
- nolmaplen = 2;
- } else {
- LANGMAP_ADJUST(c1, (State & (CMDLINE | INSERT)) == 0
- && get_real_state() != SELECTMODE);
- nolmaplen = 0;
- }
- // First try buffer-local mappings.
- mp = curbuf->b_maphash[MAP_HASH(local_State, c1)];
- mp2 = maphash[MAP_HASH(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)) {
- int nomap = nolmaplen;
- int c2;
- // find the match length of this mapping
- for (mlen = 1; mlen < typebuf.tb_len; mlen++) {
- 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) {
- 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 = (char_u *)mb_unescape((const char **)&p1);
+ // Check for a mapping in "typebuf".
+ map_result_T result = (map_result_T)handle_mapping(&keylen, &timedout, &mapdepth);
- if (p2 != NULL && MB_BYTE2LEN(c1) > utfc_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]
- != 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
- || (keylen == mp_match_len
- && mp_match != NULL
- && (mp_match->m_mode & LANGMAP) == 0
- && (mp->m_mode & LANGMAP) != 0)) {
- // 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;
- }
- }
-
- if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL))) {
- bool match = typebuf_match_len(p_pt, &mlen);
- if (match) {
- // write chars to script file(s)
- if (mlen > typebuf.tb_maplen) {
- gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
- (size_t)(mlen - typebuf.tb_maplen));
- }
-
- del_typebuf(mlen, 0); // Remove the chars.
- set_option_value("paste", !p_paste, NULL, 0);
- if (!(State & INSERT)) {
- msg_col = 0;
- msg_row = Rows - 1;
- msg_clr_eos(); // clear ruler
- }
- status_redraw_all();
- redraw_statuslines();
- showmode();
- setcursor();
- continue;
- }
- // Need more chars for partly match.
- if (mlen == typebuf.tb_len) {
- keylen = KEYLEN_PART_KEY;
- } else if (max_mlen < mlen) {
- // no match, may have to check for termcode at
- // next character
- max_mlen = mlen + 1;
- }
+ if (result == map_result_retry) {
+ // try mapping again
+ continue;
}
- if ((mp == NULL || max_mlen >= mp_match_len)
- && keylen != KEYLEN_PART_MAP) {
- // No matching mapping found or found a non-matching mapping that
- // matches at least what the matching mapping matched
- keylen = 0;
- (void)keylen; // suppress clang/dead assignment
- // If there was no mapping, use the character from the typeahead
- // buffer right here. Otherwise, use the mapping (loop around).
- 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
- } else {
- keylen = mp_match_len;
- }
+ if (result == map_result_fail) {
+ // failed, use the outer loop
+ c = -1;
+ break;
}
- // complete match
- if (keylen >= 0 && keylen <= typebuf.tb_len) {
- int save_m_expr;
- int save_m_noremap;
- int save_m_silent;
-
- // Write chars to script file(s)
- // Note: :lmap mappings are written *after* being applied. #5658
- if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) == 0) {
- gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
- (size_t)(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);
- }
-
- /* 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;
- char_u *save_m_keys = NULL; // only saved when needed
- char_u *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;
- const bool 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 {
- 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 this is a LANGMAP mapping, then we didn't record the keys
- // at the start of the function and have to record them now.
- if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) != 0) {
- gotchars(s, STRLEN(s));
- }
-
- if (save_m_noremap != REMAP_YES) {
- noremap = save_m_noremap;
- } else if (
- STRNCMP(s, save_m_keys != NULL
- ? save_m_keys : mp->m_keys,
- (size_t)keylen)
- != 0) {
- noremap = REMAP_YES;
+ 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 {
- noremap = REMAP_SKIP;
- }
- i = ins_typebuf(s, noremap,
- 0, TRUE, cmd_silent || save_m_silent);
- if (save_m_expr) {
- xfree(s);
+ 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);
}
- xfree(save_m_keys);
- xfree(save_m_str);
- if (i == FAIL) {
- c = -1;
- break;
- }
- continue;
+ break;
}
+
+ // not enough characters, get more
}
- /*
- * get a character: 3. from the user - handle <Esc> in Insert mode
- */
- /*
- * special case: if we get an <ESC> in insert mode and there
- * are no more characters at once, we pretend to go out of
- * insert mode. This prevents the one second delay after
- * typing an <ESC>. If we get something after all, we may
- * have to redisplay the mode. That the cursor is in the wrong
- * place does not matter.
- */
+ // get a character: 3. from the user - handle <Esc> in Insert mode
+
+ // special case: if we get an <ESC> in insert mode and there
+ // are no more characters at once, we pretend to go out of
+ // insert mode. This prevents the one second delay after
+ // typing an <ESC>. If we get something after all, we may
+ // have to redisplay the mode. That the cursor is in the wrong
+ // place does not matter.
c = 0;
new_wcol = curwin->w_wcol;
new_wrow = curwin->w_wrow;
@@ -2194,10 +2181,8 @@ static int vgetorpeek(bool advance)
&& ex_normal_busy == 0
&& typebuf.tb_maplen == 0
&& (State & INSERT)
- && (p_timeout
- || (keylen == KEYLEN_PART_KEY && p_ttimeout))
- && (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len,
- 3, 25L)) == 0) {
+ && (p_timeout || (keylen == KEYLEN_PART_KEY && p_ttimeout))
+ && (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len, 3, 25L)) == 0) {
colnr_T col = 0, vcol;
char_u *ptr;
@@ -2213,11 +2198,9 @@ static int vgetorpeek(bool advance)
if (curwin->w_cursor.col != 0) {
if (curwin->w_wcol > 0) {
if (did_ai) {
- /*
- * We are expecting to truncate the trailing
- * white-space, so find the last non-white
- * character -- webb
- */
+ // We are expecting to truncate the trailing
+ // white-space, so find the last non-white
+ // character -- webb
col = vcol = curwin->w_wcol = 0;
ptr = get_cursor_line_ptr();
while (col < curwin->w_cursor.col) {
@@ -2231,7 +2214,7 @@ static int vgetorpeek(bool advance)
+ curwin->w_wcol / curwin->w_width_inner;
curwin->w_wcol %= curwin->w_width_inner;
curwin->w_wcol += curwin_col_off();
- col = 0; // no correction needed
+ col = 0; // no correction needed
} else {
--curwin->w_wcol;
col = curwin->w_cursor.col - 1;
@@ -2259,7 +2242,7 @@ static int vgetorpeek(bool advance)
curwin->w_wrow = old_wrow;
}
if (c < 0) {
- continue; // end of input script reached
+ continue; // end of input script reached
}
// Allow mapping for just typed characters. When we get here c
@@ -2305,9 +2288,8 @@ static int vgetorpeek(bool advance)
break;
}
- /*
- * get a character: 3. from the user - update display
- */
+ // get a character: 3. from the user - update display
+
// In insert mode a screen update is skipped when characters
// are still available. But when those available characters
// are part of a mapping, and we are going to do a blocking
@@ -2318,26 +2300,21 @@ static int vgetorpeek(bool advance)
if (((State & INSERT) != 0 || p_lz) && (State & CMDLINE) == 0
&& advance && must_redraw != 0 && !need_wait_return) {
update_screen(0);
- setcursor(); // put cursor back where it belongs
+ setcursor(); // put cursor back where it belongs
}
- /*
- * If we have a partial match (and are going to wait for more
- * input from the user), show the partially matched characters
- * to the user with showcmd.
- */
- i = 0;
+ // If we have a partial match (and are going to wait for more
+ // input from the user), show the partially matched characters
+ // to the user with showcmd.
+ int showcmd_idx = 0;
c1 = 0;
if (typebuf.tb_len > 0 && advance && !exmode_active) {
- if (((State & (NORMAL | INSERT)) || State == LANGMAP)
- && State != HITRETURN) {
+ if (((State & (NORMAL | INSERT)) || State == LANGMAP) && State != HITRETURN) {
// this looks nice when typing a dead character map
if (State & INSERT
- && ptr2cells(typebuf.tb_buf + typebuf.tb_off
- + typebuf.tb_len - 1) == 1) {
- edit_putchar(typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1],
- false);
- setcursor(); // put cursor back where it belongs
+ && ptr2cells(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len - 1) == 1) {
+ edit_putchar(typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1], false);
+ setcursor(); // put cursor back where it belongs
c1 = 1;
}
// need to use the col and row from above here
@@ -2347,11 +2324,10 @@ static int vgetorpeek(bool advance)
curwin->w_wrow = new_wrow;
push_showcmd();
if (typebuf.tb_len > SHOWCMD_COLS) {
- i = typebuf.tb_len - SHOWCMD_COLS;
+ showcmd_idx = typebuf.tb_len - SHOWCMD_COLS;
}
- while (i < typebuf.tb_len) {
- (void)add_to_showcmd(typebuf.tb_buf[typebuf.tb_off
- + i++]);
+ while (showcmd_idx < typebuf.tb_len) {
+ (void)add_to_showcmd(typebuf.tb_buf[typebuf.tb_off + showcmd_idx++]);
}
curwin->w_wcol = old_wcol;
curwin->w_wrow = old_wrow;
@@ -2367,9 +2343,7 @@ static int vgetorpeek(bool advance)
}
}
- /*
- * get a character: 3. from the user - get it
- */
+ // get a character: 3. from the user - get it
if (typebuf.tb_len == 0) {
// timedout may have been set while waiting for a mapping
// that has a <Nop> RHS.
@@ -2379,8 +2353,7 @@ static int vgetorpeek(bool advance)
long wait_time = 0;
if (advance) {
- if (typebuf.tb_len == 0
- || !(p_timeout || (p_ttimeout && keylen == KEYLEN_PART_KEY))) {
+ if (typebuf.tb_len == 0 || !(p_timeout || (p_ttimeout && keylen == KEYLEN_PART_KEY))) {
// blocking wait
wait_time = -1L;
} else if (keylen == KEYLEN_PART_KEY && p_ttm >= 0) {
@@ -2395,7 +2368,7 @@ static int vgetorpeek(bool advance)
typebuf.tb_buflen - typebuf.tb_off - typebuf.tb_len - 1,
wait_time);
- if (i != 0) {
+ if (showcmd_idx != 0) {
pop_showcmd();
}
if (c1 == 1) {
@@ -2405,47 +2378,45 @@ static int vgetorpeek(bool advance)
if (State & CMDLINE) {
unputcmdline();
} else {
- setcursor(); // put cursor back where it belongs
+ setcursor(); // put cursor back where it belongs
}
}
if (c < 0) {
- continue; // end of input script reached
+ continue; // end of input script reached
}
- if (c == NUL) { // no character available
+ if (c == NUL) { // no character available
if (!advance) {
break;
}
- if (wait_tb_len > 0) { // timed out
+ if (wait_tb_len > 0) { // timed out
timedout = true;
continue;
}
- } else { // allow mapping for just typed characters
+ } else { // allow mapping for just typed characters
while (typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] != NUL) {
typebuf.tb_noremap[typebuf.tb_off + typebuf.tb_len++] = RM_YES;
}
}
- } // for (;;)
- } // if (!character from stuffbuf)
+ } // for (;;)
+ } // if (!character from stuffbuf)
// if advance is false don't loop on NULs
} while (c < 0 || (advance && c == NUL));
- /*
- * The "INSERT" message is taken care of here:
- * if we return an ESC to exit insert mode, the message is deleted
- * if we don't return an ESC but deleted the message before, redisplay it
- */
+ // The "INSERT" message is taken care of here:
+ // if we return an ESC to exit insert mode, the message is deleted
+ // if we don't return an ESC but deleted the message before, redisplay it
if (advance && p_smd && msg_silent == 0 && (State & INSERT)) {
if (c == ESC && !mode_deleted && !no_mapping && mode_displayed) {
if (typebuf.tb_len && !KeyTyped) {
- redraw_cmdline = true; // delete mode later
+ redraw_cmdline = true; // delete mode later
} else {
unshowmode(false);
}
} else if (c != ESC && mode_deleted) {
if (typebuf.tb_len && !KeyTyped) {
- redraw_cmdline = true; // show mode later
+ redraw_cmdline = true; // show mode later
} else {
showmode();
}