📄 getchar.c
字号:
c2 = vgetorpeek(TRUE); /* no mapping for these chars */
c = vgetorpeek(TRUE);
--no_mapping;
if (c2 == KS_MODIFIER)
{
mod_mask = c;
continue;
}
c = TO_SPECIAL(c2, c);
#ifdef USE_GUI_WIN32
/* Handle K_TEAROFF here, the caller of vgetc() doesn't need to
* know that a menu was torn off */
if (c == K_TEAROFF)
{
char_u name[200];
int i;
/* get menu path, it ends with a <CR> */
for (i = 0; (c = vgetorpeek(TRUE)) != '\r'; )
{
name[i] = c;
if (i < 199)
++i;
}
name[i] = NUL;
gui_make_tearoff(name);
continue;
}
#endif
}
#ifdef MSDOS
/*
* If K_NUL was typed, it is replaced by K_NUL, 3 in mch_inchar().
* Delete the 3 here.
*/
else if (c == K_NUL && vpeekc() == 3)
(void)vgetorpeek(TRUE);
#endif
return c;
}
}
int
vpeekc()
{
return (vgetorpeek(FALSE));
}
/*
* Call vpeekc() without causing anything to be mapped.
* Return TRUE if a character is available, FALSE otherwise.
*/
int
char_avail()
{
int retval;
++no_mapping;
retval = vgetorpeek(FALSE);
--no_mapping;
return (retval != NUL);
}
void
vungetc(c) /* unget one character (can only be done once!) */
int c;
{
old_char = c;
}
/*
* get a character: 1. from a previously ungotten character
* 2. from the stuffbuffer
* 3. from the typeahead buffer
* 4. from the user
*
* if "advance" is TRUE (vgetc()):
* really get the character.
* KeyTyped is set to TRUE in the case the user typed the key.
* KeyStuffed is TRUE if the character comes from the stuff buffer.
* if "advance" is FALSE (vpeekc()):
* just look whether there is a character available.
*/
static int
vgetorpeek(advance)
int advance;
{
int c, c1;
int keylen = 0; /* init for gcc */
char_u *s;
struct mapblock *mp;
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;
#ifdef SHOWCMD
int i;
int new_wcol, new_wrow;
#endif
#ifdef USE_GUI
int idx;
int shape_changed = FALSE; /* adjusted cursor shape */
#endif
int n;
#ifdef HAVE_LANGMAP
int c2;
#endif
int old_wcol, old_wrow;
/*
* 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().
*/
if (vgetc_busy)
return NUL;
local_State = get_real_state();
/*
* get a character: 1. from a previously ungotten character
*/
if (old_char >= 0)
{
c = old_char;
if (advance)
old_char = -1;
return c;
}
vgetc_busy = TRUE;
if (advance)
KeyStuffed = FALSE;
init_typebuf();
start_stuff();
if (advance && typemaplen == 0)
Exec_reg = FALSE;
do
{
/*
* get a character: 2. from the stuffbuffer
*/
c = read_stuff(advance);
if (c != NUL && !got_int)
{
if (advance)
{
KeyTyped = FALSE;
KeyStuffed = TRUE;
}
if (no_abbr_cnt == 0)
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.
*/
for (;;)
{
/*
* ui_breakcheck() is slow, don't use it too often when
* inside a mapping. But call it each time for typed
* characters.
*/
if (typemaplen)
line_breakcheck();
else
ui_breakcheck(); /* check for CTRL-C */
if (got_int)
{
/* flush all input */
c = inchar(typebuf, typebuflen - 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.
* As a result typing CTRL-C in insert mode will
* really insert a CTRL-C.
*/
if ((c || typemaplen) && (State & (INSERT + CMDLINE)))
c = ESC;
else
c = Ctrl('C');
flush_buffers(TRUE); /* flush all typeahead */
break;
}
else if (typelen > 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:
* - timed out
* - no_mapping set: mapping disabled (e.g. for CTRL-V)
* - maphash_valid not set: no mappings present.
* - typebuf[typeoff] 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;
if (!timedout && no_mapping == 0 && maphash_valid
&& (typemaplen == 0 ||
(p_remap && noremapbuf[typeoff] == FALSE))
&& !(p_paste && (State & (INSERT + CMDLINE)))
&& !(State == HITRETURN && (typebuf[typeoff] == CR
|| typebuf[typeoff] == ' '))
&& State != ASKMORE
&& State != CONFIRM
#ifdef INSERT_EXPAND
&& !(ctrl_x_mode
&& vim_is_ctrl_x_key(typebuf[typeoff]))
#endif
)
{
c1 = typebuf[typeoff];
#ifdef HAVE_LANGMAP
LANGMAP_ADJUST(c1, TRUE);
#endif
for (mp = maphash[MAP_HASH(local_State, c1)];
mp != NULL; mp = mp->m_next)
{
/*
* Only consider an entry if the first character
* matches and it is for the current state.
*/
if (mp->m_keys[0] == c1 &&
(mp->m_mode & local_State))
{
/* find the match length of this mapping */
for (mlen = 1; mlen < typelen; ++mlen)
{
#ifdef HAVE_LANGMAP
c2 = typebuf[typeoff + mlen];
LANGMAP_ADJUST(c2, TRUE);
if (mp->m_keys[mlen] != c2)
#else
if (mp->m_keys[mlen] !=
typebuf[typeoff + mlen])
#endif
break;
}
/*
* Check an entry whether it matches.
* - Full match: mlen == keylen
* - Partly match: mlen == typelen
*/
keylen = mp->m_keylen;
if (mlen == keylen ||
(mlen == typelen && typelen < keylen))
{
/*
* If one of the typed keys cannot be
* remapped, skip the entry.
*/
s = noremapbuf + typeoff;
for (n = mlen; --n >= 0; )
if (*s++)
break;
if (n >= 0)
continue;
/*
* Need more chars for partly match.
*/
if (keylen > typelen)
keylen = M_NEEDMORET;
break;
}
/*
* no match, may have to check for termcode at
* next character
*/
if (max_mlen < mlen)
max_mlen = mlen;
}
}
}
if (mp == NULL) /* no matching mapping found */
{
/*
* 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) &&
(typemaplen == 0 ||
(p_remap && !noremapbuf[typeoff])) &&
!timedout)
{
keylen = check_termcode(max_mlen + 1);
/*
* 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 && typelen == typemaplen)
keylen = 0;
}
else
keylen = 0;
if (keylen == 0) /* no matching terminal code */
{
#ifdef AMIGA /* check for window bounds report */
if (typemaplen == 0 &&
(typebuf[typeoff] & 0xff) == CSI)
{
for (s = typebuf + typeoff + 1;
s < typebuf + typeoff + typelen &&
(isdigit(*s) || *s == ';' || *s == ' ');
++s)
;
if (*s == 'r' || *s == '|') /* found one */
{
del_typebuf((int)(s + 1 -
(typebuf + typeoff)), 0);
/* get size and redraw screen */
set_winsize(0, 0, FALSE);
continue;
}
if (*s == NUL) /* need more characters */
keylen = K_NEEDMORET;
}
if (keylen >= 0)
#endif
{
/*
* get a character: 3. from the typeahead buffer
*/
c = typebuf[typeoff] & 255;
if (advance) /* remove chars from typebuf */
{
if (typemaplen)
KeyTyped = FALSE;
else
{
KeyTyped = TRUE;
++maptick;
/* write char to script file(s) */
gotchars(typebuf + typeoff, 1);
}
del_typebuf(1, 0);
}
break; /* got character, break for loop */
}
}
if (keylen > 0) /* full matching terminal code */
{
#ifdef USE_GUI
if (typebuf[typeoff] == K_SPECIAL &&
typebuf[typeoff + 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 = gui_get_menu_index(current_menu,
local_State);
if (idx != MENU_INDEX_INVALID)
{
/*
* In Select mode, 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)
{
VIsual_select = FALSE;
(void)ins_typebuf(K_SELECT_STRING, -1,
0, TRUE);
}
ins_typebuf(current_menu->strings[idx],
current_menu->noremap[idx] ? -1 : 0,
0, TRUE);
}
}
#endif /* USE_GUI */
continue; /* try mapping again */
}
/* partial match: get some more characters */
keylen = K_NEEDMORET;
}
/* complete match */
if (keylen >= 0 && keylen <= typelen)
{
/* write chars to script file(s) */
if (keylen > typemaplen)
gotchars(typebuf + typeoff + typemaplen,
keylen - typemaplen);
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("recursive mapping");
if (State == CMDLINE)
redrawcmdline();
else
setcursor();
flush_buffers(FALSE);
mapdepth = 0; /* for next one */
c = -1;
break;
}
/*
* In Select mode, 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)
{
VIsual_select = FALSE;
(void)ins_typebuf(K_SELECT_STRING, -1, 0, TRUE);
}
/*
* Insert the 'to' part in the typebuf.
* If 'from' field is the same as the start of the
* 'to' field, don't remap the first character.
* If m_noremap is set, don't remap the whole 'to'
* part.
*/
if (ins_typebuf(mp->m_str,
mp->m_noremap ? -1
: STRNCMP(mp->m_str, mp->m_keys,
(size_t)keylen) ? 0 : 1,
0, TRUE) == FAIL)
{
c = -1;
break;
}
continue;
}
}
/*
* 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;
#ifdef SHOWCMD
new_wcol = curwin->w_wcol;
new_wrow = curwin->w_wrow;
#endif
if ( advance
&& typelen == 1
&& typebuf[typeoff] == ESC
&& !no_mapping
&& typemaplen == 0
&& (State & INSERT)
&& (p_timeout || (keylen == K_NEEDMORET && p_ttimeout))
&& (c = inchar(typebuf + typeoff + typelen, 3, 25L))
== 0)
{
colnr_t col, vcol;
char_u *ptr;
if (p_smd)
{
unshowmode(TRUE);
mode_deleted = TRUE;
}
#ifdef USE_GUI
/* may show different cursor shape */
if (gui.in_use)
{
int save_State;
save_State = State;
State = NORMAL;
gui_update_cursor(TRUE, FALSE);
State = save_State;
shape_changed = TRUE;
}
#endif
validate_cursor();
old_wcol = curwin->w_wcol;
old_wrow = curwin->w_wrow;
/* move cursor left, if possible */
if (curwin->w_cursor.col != 0)
{
if (curwin->w_wcol)
{
if (did_ai)
{
/*
* We are expecting to truncate the trailing
* white-space, so find the last non-white
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -