📄 getchar.c
字号:
* character -- webb
*/
col = vcol = curwin->w_wcol = 0;
ptr = ml_get_curline();
while (col < curwin->w_cursor.col)
{
if (!vim_iswhite(ptr[col]))
curwin->w_wcol = vcol;
vcol += lbr_chartabsize(ptr + col,
(colnr_t)vcol);
++col;
}
if (curwin->w_p_nu)
curwin->w_wcol += 8;
}
else
--curwin->w_wcol;
}
else if (curwin->w_p_wrap && curwin->w_wrow)
{
--curwin->w_wrow;
curwin->w_wcol = Columns - 1;
}
}
setcursor();
out_flush();
#ifdef SHOWCMD
new_wcol = curwin->w_wcol;
new_wrow = curwin->w_wrow;
#endif
curwin->w_wcol = old_wcol;
curwin->w_wrow = old_wrow;
}
if (c < 0)
continue; /* end of input script reached */
typelen += c;
/* buffer full, don't map */
if (typelen >= typemaplen + MAXMAPLEN)
{
timedout = TRUE;
continue;
}
/*
* get a character: 4. from the user
*/
#ifdef SHOWCMD
/*
* 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 -- webb.
*/
i = 0;
if (typelen > 0 && (State & (NORMAL | INSERT)) &&
advance && !exmode_active)
{
/* need to use the col and row from above here */
old_wcol = curwin->w_wcol;
old_wrow = curwin->w_wrow;
curwin->w_wcol = new_wcol;
curwin->w_wrow = new_wrow;
push_showcmd();
if (typelen > SHOWCMD_COLS)
i = typelen - SHOWCMD_COLS;
while (i < typelen)
(void)add_to_showcmd(typebuf[typeoff + i++]);
curwin->w_wcol = old_wcol;
curwin->w_wrow = old_wrow;
}
#endif
c = inchar(typebuf + typeoff + typelen,
typebuflen - typeoff - typelen - 1,
!advance
? 0
: ((typelen == 0 || !(p_timeout || (p_ttimeout &&
keylen == K_NEEDMORET)))
? -1L
: ((keylen == K_NEEDMORET && p_ttm >= 0)
? p_ttm
: p_tm)));
#ifdef SHOWCMD
if (i)
pop_showcmd();
#endif
if (c < 0)
continue; /* end of input script reached */
if (c == NUL) /* no character available */
{
if (!advance)
break;
if (typelen) /* timed out */
{
timedout = TRUE;
continue;
}
}
else
{ /* allow mapping for just typed characters */
while (typebuf[typeoff + typelen] != NUL)
noremapbuf[typeoff + typelen++] = FALSE;
}
} /* 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
*/
if (advance && p_smd && (State & INSERT))
{
if (c == ESC && !mode_deleted && !no_mapping)
{
if (typelen && !KeyTyped)
redraw_cmdline = TRUE; /* delete mode later */
else
unshowmode(FALSE);
}
else if (c != ESC && mode_deleted)
{
if (typelen && !KeyTyped)
redraw_cmdline = TRUE; /* show mode later */
else
showmode();
}
}
#ifdef USE_GUI
/* may unshow different cursor shape */
if (gui.in_use && shape_changed)
gui_update_cursor(TRUE, FALSE);
#endif
vgetc_busy = FALSE;
return c;
}
/*
* inchar() - get one character from
* 1. a scriptfile
* 2. the keyboard
*
* As much characters as we can get (upto 'maxlen') are put in buf and
* NUL terminated (buffer length must be 'maxlen' + 1).
* Minimum for 'maxlen' is 3!!!!
*
* If we got an interrupt all input is read until none is available.
*
* If wait_time == 0 there is no waiting for the char.
* If wait_time == n we wait for n msec for a character to arrive.
* If wait_time == -1 we wait forever for a character to arrive.
*
* Return the number of obtained characters.
* Return -1 when end of input script reached.
*/
int
inchar(buf, maxlen, wait_time)
char_u *buf;
int maxlen;
long wait_time; /* milli seconds */
{
int len = 0; /* init for GCC */
int retesc = FALSE; /* return ESC with gotint */
int c;
int i;
if (wait_time == -1L || wait_time > 100L) /* flush output before waiting */
{
cursor_on();
out_flush();
}
/*
* Don't reset these when at the hit-return prompt, otherwise a endless
* recursive loop may result (write error in swapfile, hit-return, timeout
* on char wait, flush swapfile, write error....).
*/
if (State != HITRETURN)
{
did_outofmem_msg = FALSE; /* display out of memory message (again) */
did_swapwrite_msg = FALSE; /* display swap file write error again */
}
undo_off = FALSE; /* restart undo now */
/*
* first try script file
* If interrupted: Stop reading script files.
*/
c = -1;
while (scriptin[curscript] != NULL && c < 0)
{
if (got_int || (c = getc(scriptin[curscript])) < 0) /* reached EOF */
{
closescript();
/*
* When reading script file is interrupted, return an ESC to get
* back to normal mode.
* Otherwise return -1, because typebuf[] has changed.
*/
if (got_int)
retesc = TRUE;
else
return -1;
}
else
{
buf[0] = c;
len = 1;
}
}
if (c < 0) /* did not get a character from script */
{
/*
* If we got an interrupt, skip all previously typed characters and
* return TRUE if quit reading script file.
*/
if (got_int)
{
while (ui_inchar(buf, maxlen, 0L))
;
return retesc;
}
/*
* Always flush the output characters when getting input characters
* from the user.
*/
out_flush();
/*
* fill up to a third of the buffer, because each character may be
* tripled below
*/
len = ui_inchar(buf, maxlen / 3, wait_time);
}
/*
* Two characters are special: NUL and K_SPECIAL.
* Replace NUL by K_SPECIAL KS_ZERO K_FILLER
* Replace K_SPECIAL by K_SPECIAL KS_SPECIAL K_FILLER
* Don't replace K_SPECIAL when reading a script file.
*/
for (i = len; --i >= 0; ++buf)
{
#ifdef USE_GUI
/* Any character can come after a CSI, don't escape it. */
if (buf[0] == CSI && i >= 2)
{
buf += 2;
i -= 2;
continue;
}
#endif
if (buf[0] == NUL || (buf[0] == K_SPECIAL && c < 0))
{
mch_memmove(buf + 3, buf + 1, (size_t)i);
buf[2] = K_THIRD(buf[0]);
buf[1] = K_SECOND(buf[0]);
buf[0] = K_SPECIAL;
buf += 2;
len += 2;
}
}
*buf = NUL; /* add trailing NUL */
return len;
}
/*
* map[!] : show all key mappings
* map[!] {lhs} : show key mapping for {lhs}
* map[!] {lhs} {rhs} : set key mapping for {lhs} to {rhs}
* noremap[!] {lhs} {rhs} : same, but no remapping for {rhs}
* unmap[!] {lhs} : remove key mapping for {lhs}
* abbr : show all abbreviations
* abbr {lhs} : show abbreviations for {lhs}
* abbr {lhs} {rhs} : set abbreviation for {lhs} to {rhs}
* noreabbr {lhs} {rhs} : same, but no remapping for {rhs}
* unabbr {lhs} : remove abbreviation for {lhs}
*
* maptype == 1 for unmap command, 2 for noremap command.
*
* keys is pointer to any arguments. Note: keys cannot be a read-only string,
* it will be modified.
*
* for :map mode is NORMAL + VISUAL + OP_PENDING
* for :map! mode is INSERT + CMDLINE
* for :cmap mode is CMDLINE
* for :imap mode is INSERT
* for :nmap mode is NORMAL
* for :vmap mode is VISUAL
* for :omap mode is OP_PENDING
*
* for :abbr mode is INSERT + CMDLINE
* for :iabbr mode is INSERT
* for :cabbr mode is CMDLINE
*
* Return 0 for success
* 1 for invalid arguments
* 2 for no match
* 3 for ambiguety
* 4 for out of mem
*/
int
do_map(maptype, keys, mode, abbrev)
int maptype;
char_u *keys;
int mode;
int abbrev; /* not a mapping but an abbreviation */
{
struct mapblock *mp, **mpp;
char_u *arg;
char_u *p;
int n;
int len = 0; /* init for GCC */
char_u *newstr;
int hasarg;
int haskey;
int did_it = FALSE;
int round;
char_u *keys_buf = NULL;
char_u *arg_buf = NULL;
int retval = 0;
int do_backslash;
int hash;
int new_hash;
validate_maphash();
/*
* find end of keys and skip CTRL-Vs (and backslashes) in it
* Accept backslash like CTRL-V when 'cpoptions' does not contain 'B'.
* with :unmap white space is included in the keys, no argument possible
*/
p = keys;
do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
while (*p && (maptype == 1 || !vim_iswhite(*p)))
{
if ((p[0] == Ctrl('V') || (do_backslash && p[0] == '\\')) &&
p[1] != NUL)
++p; /* skip CTRL-V or backslash */
++p;
}
if (*p != NUL)
*p++ = NUL;
p = skipwhite(p);
arg = p;
hasarg = (*arg != NUL);
haskey = (*keys != NUL);
/* check for :unmap without argument */
if (maptype == 1 && !haskey)
{
retval = 1;
goto theend;
}
/*
* If mapping has been given as ^V<C_UP> say, then replace the term codes
* with the appropriate two bytes. If it is a shifted special key, unshift
* it too, giving another two bytes.
* replace_termcodes() may move the result to allocated memory, which
* needs to be freed later (*keys_buf and *arg_buf).
* replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
*/
if (haskey)
keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE);
if (hasarg)
{
if (STRICMP(arg, "<nop>") == 0) /* "<Nop>" means nothing */
arg = (char_u *)"";
else
arg = replace_termcodes(arg, &arg_buf, FALSE, TRUE);
}
#ifdef FKMAP
/*
* when in right-to-left mode and alternate keymap option set,
* reverse the character flow in the arg in Farsi.
*/
if (p_altkeymap && curwin->w_p_rl)
lrswap(arg);
#endif
/*
* check arguments and translate function keys
*/
if (haskey)
{
len = STRLEN(keys);
if (len > MAXMAPLEN) /* maximum length of MAXMAPLEN chars */
{
retval = 1;
goto theend;
}
if (abbrev && maptype != 1)
{
/*
* If an abbreviation ends in a keyword character, the
* rest must be all keyword-char or all non-keyword-char.
* Otherwise we won't be able to find the start of it in a
* vi-compatible way.
* An abbrevation cannot contain white space.
*/
if (vim_iswordc(keys[len - 1])) /* ends in keyword char */
for (n = 0; n < len - 2; ++n)
if (vim_iswordc(keys[n]) != vim_iswordc(keys[len - 2]))
{
retval = 1;
goto theend;
}
for (n = 0; n < len; ++n)
if (vim_iswhite(keys[n]))
{
retval = 1;
goto theend;
}
}
}
if (haskey && hasarg && abbrev) /* if we will add an abbreviation */
no_abbr = FALSE; /* reset flag that indicates there are
no abbreviations */
if (!haskey || (maptype != 1 && !hasarg))
msg_start();
/*
* Find an entry in the maphash[] list that matches.
* For :unmap we may loop two times: once to try to unmap an entry with a
* matching 'from' part, a second time, if the first fails, to unmap an
* entry with a matching 'to' part. This was done to allow ":ab foo bar"
* to be unmapped by typing ":unab foo", where "foo" will be replaced by
* "bar" because of the abbreviation.
*/
for (round = 0; (round == 0 || maptype == 1) && round <= 1 &&
!did_it && !got_int; ++round)
{
/* need to loop over all hash lists */
for (hash = 0; hash < 256 && !got_int; ++hash)
{
if (abbrev)
{
if (hash) /* there is only one abbreviation list */
break;
mpp = &first_abbr;
}
else
mpp = &(maphash[hash]);
for (mp = *mpp; mp != NULL && !got_int; mp = *mpp)
{
if (!(mp->m_mode & mode)) /* skip entries with wrong mode */
{
mpp = &(mp->m_next);
continue;
}
if (!haskey) /* show all entries */
{
showmap(mp);
did_it = TRUE;
}
else /* do we have a match? */
{
if (round) /* second round: Try unmap "rhs" string */
{
n = STRLEN(mp->m_str);
p = mp->m_str;
}
else
{
n = mp->m_keylen;
p = mp->m_keys;
}
if (!STRNCMP(p, keys, (size_t)(n < len ? n : len)))
{
if (maptype == 1) /* delete entry */
{
if (n != len) /* not a full match */
{
mpp = &(mp->m_next);
continue;
}
/*
* We reset the indicated mode bits. If nothing is
* left the entry is deleted below.
*/
mp->m_mode &= ~mode;
did_it = TRUE; /* remember we did something */
}
else if (!hasarg) /* show matching entry */
{
showmap(mp);
did_it = TRUE;
}
else if (n != len) /* new entry is ambigious */
{
if (abbrev) /* for abbrev's that's ok */
{
mpp = &(mp->m_next);
continue;
}
retval = 3;
goto theend;
}
else /* new rhs for existing entry */
{
mp->m_mode &= ~mode; /* remove mode bits */
if (mp->m_mode == 0 && !did_it) /* reuse entry */
{
newstr = vim_strsave(arg);
if (newstr == NULL)
{
retval = 4; /* no mem */
goto theend;
}
vim_free(mp->m_str);
mp->m_str = newstr;
mp->m_noremap = maptype;
mp->m_mode = mode;
did_it = TRUE;
}
}
if (mp->m_mode == 0) /* entry can be deleted */
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -