📄 getchar.c
字号:
/*
* copy the rest of the redo buffer into the stuff buffer (could be done faster)
* if old_redo is TRUE, use old_redobuff instead of redobuff
*/
static void
copy_redo(old_redo)
int old_redo;
{
int c;
while ((c = read_redo(FALSE, old_redo)) != NUL)
stuffcharReadbuff(c);
}
/*
* Stuff the redo buffer into the stuffbuff.
* Insert the redo count into the command.
* If 'old_redo' is TRUE, the last but one command is repeated
* instead of the last command (inserting text). This is used for
* CTRL-O <.> in insert mode
*
* return FAIL for failure, OK otherwise
*/
int
start_redo(count, old_redo)
long count;
int old_redo;
{
int c;
/* init the pointers; return if nothing to redo */
if (read_redo(TRUE, old_redo) == FAIL)
return FAIL;
c = read_redo(FALSE, old_redo);
/* copy the buffer name, if present */
if (c == '"')
{
add_buff(&stuffbuff, (char_u *)"\"");
c = read_redo(FALSE, old_redo);
/* if a numbered buffer is used, increment the number */
if (c >= '1' && c < '9')
++c;
add_char_buff(&stuffbuff, c);
c = read_redo(FALSE, old_redo);
}
if (c == 'v') /* redo Visual */
{
VIsual = curwin->w_cursor;
VIsual_active = TRUE;
VIsual_reselect = TRUE;
redo_VIsual_busy = TRUE;
c = read_redo(FALSE, old_redo);
}
/* try to enter the count (in place of a previous count) */
if (count)
{
while (isdigit(c)) /* skip "old" count */
c = read_redo(FALSE, old_redo);
add_num_buff(&stuffbuff, count);
}
/* copy from the redo buffer into the stuff buffer */
add_char_buff(&stuffbuff, c);
copy_redo(old_redo);
return OK;
}
/*
* Repeat the last insert (R, o, O, a, A, i or I command) by stuffing
* the redo buffer into the stuffbuff.
* return FAIL for failure, OK otherwise
*/
int
start_redo_ins()
{
int c;
if (read_redo(TRUE, FALSE) == FAIL)
return FAIL;
start_stuff();
/* skip the count and the command character */
while ((c = read_redo(FALSE, FALSE)) != NUL)
{
if (vim_strchr((char_u *)"AaIiRrOo", c) != NULL)
{
if (c == 'O' || c == 'o')
stuffReadbuff(NL_STR);
break;
}
}
/* copy the typed text from the redo buffer into the stuff buffer */
copy_redo(FALSE);
block_redo = TRUE;
return OK;
}
void
set_redo_ins()
{
block_redo = TRUE;
}
void
stop_redo_ins()
{
block_redo = FALSE;
}
/*
* Initialize typebuf to point to typebuf_init.
* Alloc() cannot be used here: In out-of-memory situations it would
* be impossible to type anything.
*/
static void
init_typebuf()
{
if (typebuf == NULL)
{
typebuf = typebuf_init;
noremapbuf = noremapbuf_init;
typebuflen = TYPELEN_INIT;
typelen = 0;
typeoff = 0;
}
}
/*
* insert a string in position 'offset' in the typeahead buffer (for "@r"
* and ":normal" command, vgetorpeek() and check_termcode())
*
* If noremap is 0, new string can be mapped again.
* If noremap is -1, new string cannot be mapped again.
* If noremap is >0, that many characters of the new string cannot be mapped.
*
* If nottyped is TRUE, the string does not return KeyTyped (don't use when
* offset is non-zero!).
*
* return FAIL for failure, OK otherwise
*/
int
ins_typebuf(str, noremap, offset, nottyped)
char_u *str;
int noremap;
int offset;
int nottyped;
{
char_u *s1, *s2;
int newlen;
int addlen;
int i;
int newoff;
init_typebuf();
addlen = STRLEN(str);
/*
* Easy case: there is room in front of typebuf[typeoff]
*/
if (offset == 0 && addlen <= typeoff)
{
typeoff -= addlen;
mch_memmove(typebuf + typeoff, str, (size_t)addlen);
}
/*
* Need to allocate new buffer.
* In typebuf there must always be room for 3 * MAXMAPLEN + 4 characters.
* We add some extra room to avoid having to allocate too often.
*/
else
{
newoff = MAXMAPLEN + 4;
newlen = typelen + addlen + newoff + 4 * (MAXMAPLEN + 4);
if (newlen < 0) /* string is getting too long */
{
emsg(e_toocompl); /* also calls flush_buffers */
setcursor();
return FAIL;
}
s1 = alloc(newlen);
if (s1 == NULL) /* out of memory */
return FAIL;
s2 = alloc(newlen);
if (s2 == NULL) /* out of memory */
{
vim_free(s1);
return FAIL;
}
typebuflen = newlen;
/* copy the old chars, before the insertion point */
mch_memmove(s1 + newoff, typebuf + typeoff, (size_t)offset);
/* copy the new chars */
mch_memmove(s1 + newoff + offset, str, (size_t)addlen);
/* copy the old chars, after the insertion point, including the NUL at
* the end */
mch_memmove(s1 + newoff + offset + addlen, typebuf + typeoff + offset,
(size_t)(typelen - offset + 1));
if (typebuf != typebuf_init)
vim_free(typebuf);
typebuf = s1;
mch_memmove(s2 + newoff, noremapbuf + typeoff, (size_t)offset);
mch_memmove(s2 + newoff + offset + addlen,
noremapbuf + typeoff + offset, (size_t)(typelen - offset));
if (noremapbuf != noremapbuf_init)
vim_free(noremapbuf);
noremapbuf = s2;
typeoff = newoff;
}
typelen += addlen;
/*
* Adjust noremapbuf[] for the new characters:
* If noremap < 0: all the new characters are flagged not remappable
* If noremap == 0: all the new characters are flagged mappable
* If noremap > 0: 'noremap' characters are flagged not remappable, the
* rest mappable
*/
if (noremap < 0) /* length not specified */
noremap = addlen;
for (i = 0; i < addlen; ++i)
noremapbuf[typeoff + i + offset] = (noremap-- > 0);
/* this is only correct for offset == 0! */
if (nottyped) /* the inserted string is not typed */
typemaplen += addlen;
if (no_abbr_cnt && offset == 0) /* and not used for abbreviations */
no_abbr_cnt += addlen;
return OK;
}
/*
* Return TRUE if there are no characters in the typeahead buffer that have
* not been typed (result from a mapping or come from ":normal").
*/
int
typebuf_typed()
{
return typemaplen == 0;
}
/*
* Return the number of characters that are mapped (or not typed).
*/
int
typebuf_maplen()
{
return typemaplen;
}
/*
* remove "len" characters from typebuf[typeoff + offset]
*/
void
del_typebuf(len, offset)
int len;
int offset;
{
int i;
typelen -= len;
/*
* Easy case: Just increase typeoff.
*/
if (offset == 0 && typebuflen - (typeoff + len) >= 3 * MAXMAPLEN + 3)
typeoff += len;
/*
* Have to move the characters in typebuf[] and noremapbuf[]
*/
else
{
i = typeoff + offset;
/*
* Leave some extra room at the end to avoid reallocation.
*/
if (typeoff > MAXMAPLEN)
{
mch_memmove(typebuf + MAXMAPLEN, typebuf + typeoff, (size_t)offset);
mch_memmove(noremapbuf + MAXMAPLEN, noremapbuf + typeoff,
(size_t)offset);
typeoff = MAXMAPLEN;
}
/* adjust typebuf (include the NUL at the end) */
mch_memmove(typebuf + typeoff + offset, typebuf + i + len,
(size_t)(typelen - offset + 1));
/* adjust noremapbuf[] */
mch_memmove(noremapbuf + typeoff + offset, noremapbuf + i + len,
(size_t)(typelen - offset));
}
if (typemaplen > offset) /* adjust typemaplen */
{
if (typemaplen < offset + len)
typemaplen = offset;
else
typemaplen -= len;
}
if (no_abbr_cnt > offset) /* adjust no_abbr_cnt */
{
if (no_abbr_cnt < offset + len)
no_abbr_cnt = offset;
else
no_abbr_cnt -= len;
}
}
/*
* Write typed characters to script file.
* If recording is on put the character in the recordbuffer.
*/
static void
gotchars(s, len)
char_u *s;
int len;
{
int c;
char_u buf[2];
/* remember how many chars were last recorded */
if (Recording)
last_recorded_len += len;
buf[1] = NUL;
while (len--)
{
c = *s++;
updatescript(c);
if (Recording)
{
buf[0] = c;
add_buff(&recordbuff, buf);
}
}
may_sync_undo();
}
/*
* Sync undo. Called when typed characters are obtained from the typeahead
* buffer, or when a menu is used.
* Do not sync:
* - In Insert mode, unless cursor key has been used.
* - While reading a script file.
* - When no_u_sync is non-zero.
*/
static void
may_sync_undo()
{
if ((!(State & (INSERT + CMDLINE)) || arrow_used) &&
scriptin[curscript] == NULL && !no_u_sync)
u_sync();
}
/*
* When doing ":so! file", the current typeahead needs to be saved, and
* restored when "file" has been read completely.
*/
static char_u *(sv_typebuf[NSCRIPT]);
static char_u *(sv_noremapbuf[NSCRIPT]);
static int sv_typebuflen[NSCRIPT];
static int sv_typeoff[NSCRIPT];
static int sv_typelen[NSCRIPT];
static int sv_typemaplen[NSCRIPT];
static int sv_no_abbr_cnt[NSCRIPT];
int
save_typebuf()
{
init_typebuf();
sv_typebuf[curscript] = typebuf;
sv_noremapbuf[curscript] = noremapbuf;
sv_typebuflen[curscript] = typebuflen;
sv_typeoff[curscript] = typeoff;
sv_typelen[curscript] = typelen;
sv_typemaplen[curscript] = typemaplen;
sv_no_abbr_cnt[curscript] = no_abbr_cnt;
typebuf = alloc(TYPELEN_INIT);
noremapbuf = alloc(TYPELEN_INIT);
typebuflen = TYPELEN_INIT;
typeoff = 0;
typelen = 0;
typemaplen = 0;
no_abbr_cnt = 0;
/* If out of memory: restore typebuf and close file. */
if (typebuf == NULL || noremapbuf == NULL)
{
closescript();
return FAIL;
}
return OK;
}
/*
* open new script file for ":so!" command
* return OK on success, FAIL on error
*/
int
openscript(name)
char_u *name;
{
int oldcurscript;
if (curscript + 1 == NSCRIPT)
{
emsg(e_nesting);
return FAIL;
}
if (scriptin[curscript] != NULL) /* already reading script */
++curscript;
/* use NameBuff for expanded name */
expand_env(name, NameBuff, MAXPATHL);
if ((scriptin[curscript] = fopen((char *)NameBuff, READBIN)) == NULL)
{
emsg2(e_notopen, name);
if (curscript)
--curscript;
return FAIL;
}
if (save_typebuf() == FAIL)
return FAIL;
/*
* With command ":g/pat/so! file" we have to execute the
* commands from the file now.
*/
if (global_busy)
{
OPARG oa;
clear_oparg(&oa);
State = NORMAL;
oldcurscript = curscript;
do
{
adjust_cursor(); /* put cursor on an existing line */
normal_cmd(&oa, FALSE);
vpeekc(); /* check for end of file */
}
while (scriptin[oldcurscript] != NULL);
State = CMDLINE;
}
return OK;
}
/*
* Close the currently active input script.
*/
static void
closescript()
{
vim_free(typebuf);
vim_free(noremapbuf);
typebuf = sv_typebuf[curscript];
noremapbuf = sv_noremapbuf[curscript];
typebuflen = sv_typebuflen[curscript];
typelen = sv_typelen[curscript];
typeoff = sv_typeoff[curscript];
typemaplen = sv_typemaplen[curscript];
no_abbr_cnt = sv_no_abbr_cnt[curscript];
fclose(scriptin[curscript]);
scriptin[curscript] = NULL;
if (curscript)
--curscript;
}
/*
* updatescipt() is called when a character can be written into the script file
* or when we have waited some time for a character (c == 0)
*
* All the changed memfiles are synced if c == 0 or when the number of typed
* characters reaches 'updatecount' and 'updatecount' is non-zero.
*/
void
updatescript(c)
int c;
{
static int count = 0;
if (c && scriptout)
putc(c, scriptout);
if (c == 0 || (p_uc > 0 && ++count >= p_uc))
{
ml_sync_all(c == 0, TRUE);
count = 0;
}
}
#define K_NEEDMORET -1 /* keylen value for incomplete key-code */
#define M_NEEDMORET -2 /* keylen value for incomplete mapping */
static int old_char = -1; /* ungotten character */
int
vgetc()
{
int c, c2;
mod_mask = 0x0;
last_recorded_len = 0;
for (;;) /* this is done twice if there are modifiers */
{
if (mod_mask) /* no mapping after modifier has been read */
{
++no_mapping;
++allow_keys;
}
c = vgetorpeek(TRUE);
if (mod_mask)
{
--no_mapping;
--allow_keys;
}
/* Get two extra bytes for special keys */
if (c == K_SPECIAL)
{
++no_mapping;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -