aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/getchar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/getchar.c')
-rw-r--r--src/nvim/getchar.c260
1 files changed, 143 insertions, 117 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 563608dd1d..94702a9a3a 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -315,7 +315,7 @@ static void add_char_buff(buffheader_T *buf, int c)
if (IS_SPECIAL(c)) {
len = 1;
} else {
- len = mb_char2bytes(c, bytes);
+ len = utf_char2bytes(c, bytes);
}
for (int i = 0; i < len; i++) {
@@ -420,7 +420,7 @@ void typeahead_noflush(int c)
* typeahead buffer (used in case of an error). If "flush_typeahead" is true,
* flush all typeahead characters (used when interrupted by a CTRL-C).
*/
-void flush_buffers(int flush_typeahead)
+void flush_buffers(flush_buffers_T flush_typeahead)
{
init_typebuf();
@@ -428,24 +428,28 @@ void flush_buffers(int flush_typeahead)
while (read_readbuffers(TRUE) != NUL) {
}
- if (flush_typeahead) { /* remove all typeahead */
- /*
- * We have to get all characters, because we may delete the first part
- * of an escape sequence.
- * In an xterm we get one char at a time and we have to get them all.
- */
- while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L,
- typebuf.tb_change_cnt) != 0)
- ;
- typebuf.tb_off = MAXMAPLEN;
- typebuf.tb_len = 0;
- } else { /* remove mapped characters at the start only */
+ if (flush_typeahead == FLUSH_MINIMAL) {
+ // remove mapped characters at the start only
typebuf.tb_off += typebuf.tb_maplen;
typebuf.tb_len -= typebuf.tb_maplen;
+ } else {
+ // remove typeahead
+ if (flush_typeahead == FLUSH_INPUT) {
+ // We have to get all characters, because we may delete the first
+ // part of an escape sequence. In an xterm we get one char at a
+ // time and we have to get them all.
+ while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L) != 0) {
+ }
+ }
+ typebuf.tb_off = MAXMAPLEN;
+ typebuf.tb_len = 0;
+ // Reset the flag that text received from a client or from feedkeys()
+ // was inserted in the typeahead buffer.
+ typebuf_was_filled = false;
}
typebuf.tb_maplen = 0;
typebuf.tb_silent = 0;
- cmd_silent = FALSE;
+ cmd_silent = false;
typebuf.tb_no_abbr_cnt = 0;
}
@@ -649,15 +653,13 @@ void stuffnumReadbuff(long n)
add_num_buff(&readbuf1, n);
}
-/*
- * Read a character from the redo buffer. Translates K_SPECIAL, CSI and
- * multibyte characters.
- * The redo buffer is left as it is.
- * If init is TRUE, prepare for redo, return FAIL if nothing to redo, OK
- * otherwise.
- * If old is TRUE, use old_redobuff instead of redobuff.
- */
-static int read_redo(int init, int old_redo)
+// Read a character from the redo buffer. Translates K_SPECIAL, CSI and
+// multibyte characters.
+// The redo buffer is left as it is.
+// If init is true, prepare for redo, return FAIL if nothing to redo, OK
+// otherwise.
+// If old_redo is true, use old_redobuff instead of redobuff.
+static int read_redo(bool init, bool old_redo)
{
static buffblock_T *bp;
static char_u *p;
@@ -698,7 +700,7 @@ static int read_redo(int init, int old_redo)
buf[i] = (char_u)c;
if (i == n - 1) { // last byte of a character
if (n != 1) {
- c = (*mb_ptr2char)(buf);
+ c = utf_ptr2char(buf);
}
break;
}
@@ -710,38 +712,35 @@ static int read_redo(int init, int old_redo)
return c;
}
-/*
- * Copy the rest of the redo buffer into the stuff buffer (in a slow way).
- * If old_redo is TRUE, use old_redobuff instead of redobuff.
- * The escaped K_SPECIAL and CSI are copied without translation.
- */
-static void copy_redo(int old_redo)
+// Copy the rest of the redo buffer into the stuff buffer (in a slow way).
+// If old_redo is true, use old_redobuff instead of redobuff.
+// The escaped K_SPECIAL and CSI are copied without translation.
+static void copy_redo(bool old_redo)
{
int c;
- while ((c = read_redo(FALSE, old_redo)) != NUL) {
+ while ((c = read_redo(false, old_redo)) != NUL) {
add_char_buff(&readbuf2, c);
}
}
-/*
- * Stuff the redo buffer into readbuf2.
- * 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(long count, int old_redo)
+// Stuff the redo buffer into readbuf2.
+// 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(long count, bool old_redo)
{
int c;
- /* init the pointers; return if nothing to redo */
- if (read_redo(TRUE, old_redo) == FAIL)
+ // init the pointers; return if nothing to redo
+ if (read_redo(true, old_redo) == FAIL) {
return FAIL;
+ }
- c = read_redo(FALSE, old_redo);
+ c = read_redo(false, old_redo);
/* copy the buffer name, if present */
if (c == '"') {
@@ -752,22 +751,30 @@ int start_redo(long count, int old_redo)
if (c >= '1' && c < '9')
++c;
add_char_buff(&readbuf2, c);
- c = read_redo(FALSE, old_redo);
+
+ // the expression register should be re-evaluated
+ if (c == '=') {
+ add_char_buff(&readbuf2, CAR);
+ cmd_silent = true;
+ }
+
+ c = read_redo(false, old_redo);
}
if (c == 'v') { /* redo Visual */
VIsual = curwin->w_cursor;
- VIsual_active = TRUE;
- VIsual_select = FALSE;
- VIsual_reselect = TRUE;
- redo_VIsual_busy = TRUE;
- c = read_redo(FALSE, old_redo);
+ VIsual_active = true;
+ VIsual_select = false;
+ VIsual_reselect = true;
+ redo_VIsual_busy = true;
+ c = read_redo(false, old_redo);
}
- /* try to enter the count (in place of a previous count) */
+ // try to enter the count (in place of a previous count)
if (count) {
- while (ascii_isdigit(c)) /* skip "old" count */
- c = read_redo(FALSE, old_redo);
+ while (ascii_isdigit(c)) { // skip "old" count
+ c = read_redo(false, old_redo);
+ }
add_num_buff(&readbuf2, count);
}
@@ -786,12 +793,13 @@ int start_redo_ins(void)
{
int c;
- if (read_redo(TRUE, FALSE) == FAIL)
+ if (read_redo(true, false) == FAIL) {
return FAIL;
+ }
start_stuff();
- /* skip the count and the command character */
- while ((c = read_redo(FALSE, FALSE)) != NUL) {
+ // 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') {
add_buff(&readbuf2, NL_STR, -1L);
@@ -800,9 +808,9 @@ int start_redo_ins(void)
}
}
- /* copy the typed text from the redo buffer into the stuff buffer */
- copy_redo(FALSE);
- block_redo = TRUE;
+ // copy the typed text from the redo buffer into the stuff buffer
+ copy_redo(false);
+ block_redo = true;
return OK;
}
@@ -949,7 +957,7 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
typebuf.tb_maplen += addlen;
if (silent || typebuf.tb_silent > offset) {
typebuf.tb_silent += addlen;
- cmd_silent = TRUE;
+ cmd_silent = true;
}
if (typebuf.tb_no_abbr_cnt && offset == 0) /* and not used for abbrev.s */
typebuf.tb_no_abbr_cnt += addlen;
@@ -972,7 +980,7 @@ void ins_char_typebuf(int c)
buf[2] = (char_u)K_THIRD(c);
buf[3] = NUL;
} else {
- buf[(*mb_char2bytes)(c, buf)] = NUL;
+ buf[utf_char2bytes(c, buf)] = NUL;
}
(void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
}
@@ -1077,9 +1085,10 @@ void del_typebuf(int len, int offset)
/* Reset the flag that text received from a client or from feedkeys()
* was inserted in the typeahead buffer. */
- typebuf_was_filled = FALSE;
- if (++typebuf.tb_change_cnt == 0)
+ typebuf_was_filled = false;
+ if (++typebuf.tb_change_cnt == 0) {
typebuf.tb_change_cnt = 1;
+ }
}
/*
@@ -1482,7 +1491,7 @@ int vgetc(void)
}
}
no_mapping--;
- c = (*mb_ptr2char)(buf);
+ c = utf_ptr2char(buf);
}
break;
@@ -1531,6 +1540,7 @@ int plain_vgetc(void)
* Check if a character is available, such that vgetc() will not block.
* If the next character is a special character or multi-byte, the returned
* character is not valid!.
+ * Returns NUL if no character is available.
*/
int vpeekc(void)
{
@@ -1595,7 +1605,8 @@ vungetc ( /* unget one character (can only be done once!) */
/// 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.
+/// Just look whether there is a character available.
+/// Return NUL if not.
///
/// When `no_mapping` (global) is zero, checks for mappings in the current mode.
/// Only returns one byte (of a multi-byte character).
@@ -1663,7 +1674,7 @@ static int vgetorpeek(int advance)
}
if (c != NUL && !got_int) {
if (advance) {
- // KeyTyped = FALSE; When the command that stuffed something
+ // KeyTyped = false; When the command that stuffed something
// was typed, behave like the stuffed command was typed.
// needed for CTRL-W CTRL-] to open a fold, for example.
KeyStuffed = true;
@@ -1689,22 +1700,20 @@ static int vgetorpeek(int advance)
os_breakcheck(); /* check for CTRL-C */
keylen = 0;
if (got_int) {
- /* flush all input */
- c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L,
- typebuf.tb_change_cnt);
- /*
- * 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.
- */
+ // 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.
+ // As a result typing CTRL-C in insert mode will
+ // really insert a CTRL-C.
if ((c || typebuf.tb_maplen)
- && (State & (INSERT + CMDLINE)))
+ && (State & (INSERT + CMDLINE))) {
c = ESC;
- else
+ } else {
c = Ctrl_C;
- flush_buffers(TRUE); /* flush all typeahead */
+ }
+ flush_buffers(FLUSH_INPUT); // flush all typeahead
if (advance) {
/* Also record this character, it might be needed to
@@ -1712,7 +1721,7 @@ static int vgetorpeek(int advance)
*typebuf.tb_buf = (char_u)c;
gotchars(typebuf.tb_buf, 1);
}
- cmd_silent = FALSE;
+ cmd_silent = false;
break;
} else if (typebuf.tb_len > 0) {
@@ -1965,8 +1974,8 @@ static int vgetorpeek(int advance)
redrawcmdline();
else
setcursor();
- flush_buffers(FALSE);
- mapdepth = 0; /* for next one */
+ flush_buffers(FLUSH_MINIMAL);
+ mapdepth = 0; // for next one
c = -1;
break;
}
@@ -2067,18 +2076,17 @@ static int vgetorpeek(int advance)
c = 0;
new_wcol = curwin->w_wcol;
new_wrow = curwin->w_wrow;
- if ( advance
- && typebuf.tb_len == 1
- && typebuf.tb_buf[typebuf.tb_off] == ESC
- && !no_mapping
- && 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,
- typebuf.tb_change_cnt)) == 0) {
+ if (advance
+ && typebuf.tb_len == 1
+ && typebuf.tb_buf[typebuf.tb_off] == ESC
+ && !no_mapping
+ && 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) {
colnr_T col = 0, vcol;
char_u *ptr;
@@ -2125,13 +2133,14 @@ static int vgetorpeek(int advance)
curwin->w_wcol = curwin->w_width - 1;
col = curwin->w_cursor.col - 1;
}
- if (has_mbyte && col > 0 && curwin->w_wcol > 0) {
- /* Correct when the cursor is on the right halve
- * of a double-wide character. */
+ if (col > 0 && curwin->w_wcol > 0) {
+ // Correct when the cursor is on the right halve
+ // of a double-wide character.
ptr = get_cursor_line_ptr();
- col -= (*mb_head_off)(ptr, ptr + col);
- if ((*mb_ptr2cells)(ptr + col) > 1)
- --curwin->w_wcol;
+ col -= utf_head_off(ptr, ptr + col);
+ if (utf_ptr2cells(ptr + col) > 1) {
+ curwin->w_wcol--;
+ }
}
}
setcursor();
@@ -2249,6 +2258,11 @@ static int vgetorpeek(int advance)
/*
* 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.
+ timedout = false;
+ }
wait_tb_len = typebuf.tb_len;
c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len,
typebuf.tb_buflen - typebuf.tb_off - typebuf.tb_len - 1,
@@ -2260,7 +2274,7 @@ static int vgetorpeek(int advance)
? -1L
: ((keylen == KEYLEN_PART_KEY && p_ttm >= 0)
? p_ttm
- : p_tm)), typebuf.tb_change_cnt);
+ : p_tm)));
if (i != 0)
pop_showcmd();
@@ -2341,16 +2355,15 @@ static int vgetorpeek(int advance)
* Return the number of obtained characters.
* Return -1 when end of input script reached.
*/
-int
-inchar (
+int inchar(
char_u *buf,
int maxlen,
- long wait_time, /* milli seconds */
- int tb_change_cnt
+ long wait_time // milli seconds
)
{
int len = 0; // Init for GCC.
int retesc = false; // Return ESC with gotint.
+ const int tb_change_cnt = typebuf.tb_change_cnt;
if (wait_time == -1L || wait_time > 100L) {
// flush output before waiting
@@ -2421,10 +2434,19 @@ inchar (
len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt);
}
+ // If the typebuf was changed further down, it is like nothing was added by
+ // this call.
if (typebuf_changed(tb_change_cnt)) {
return 0;
}
+ // Note the change in the typeahead buffer, this matters for when
+ // vgetorpeek() is called recursively, e.g. using getchar(1) in a timer
+ // function.
+ if (len > 0 && ++typebuf.tb_change_cnt == 0) {
+ typebuf.tb_change_cnt = 1;
+ }
+
return fix_input_buffer(buf, len);
}
@@ -3637,16 +3659,14 @@ int check_abbr(int c, char_u *ptr, int col, int mincol)
tb[j++] = (char_u)K_SECOND(c);
tb[j++] = (char_u)K_THIRD(c);
} else {
- if (c < ABBR_OFF && (c < ' ' || c > '~'))
- tb[j++] = Ctrl_V; /* special char needs CTRL-V */
- if (has_mbyte) {
- /* if ABBR_OFF has been added, remove it here */
- if (c >= ABBR_OFF)
- c -= ABBR_OFF;
- j += (*mb_char2bytes)(c, tb + j);
- } else {
- tb[j++] = (char_u)c;
+ if (c < ABBR_OFF && (c < ' ' || c > '~')) {
+ tb[j++] = Ctrl_V; // special char needs CTRL-V
+ }
+ // if ABBR_OFF has been added, remove it here.
+ if (c >= ABBR_OFF) {
+ c -= ABBR_OFF;
}
+ j += utf_char2bytes(c, tb + j);
}
tb[j] = NUL;
/* insert the last typed char */
@@ -4299,8 +4319,14 @@ char_u * getcmdkeycmd(int promptc, void *cookie, int indent)
EMSG(e_cmdmap_repeated);
aborted = true;
} else if (IS_SPECIAL(c1)) {
- EMSG2(e_cmdmap_key, get_special_key_name(c1, cmod));
- aborted = true;
+ if (c1 == K_SNR) {
+ ga_append(&line_ga, (char)K_SPECIAL);
+ ga_append(&line_ga, (char)KS_EXTRA);
+ ga_append(&line_ga, (char)KE_SNR);
+ } else {
+ EMSG2(e_cmdmap_key, get_special_key_name(c1, cmod));
+ aborted = true;
+ }
} else {
ga_append(&line_ga, (char)c1);
}