aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/getchar.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
commit1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch)
treecd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/getchar.c
parenteaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-aucmd_textputpost.tar.gz
rneovim-aucmd_textputpost.tar.bz2
rneovim-aucmd_textputpost.zip
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/getchar.c')
-rw-r--r--src/nvim/getchar.c683
1 files changed, 333 insertions, 350 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 8ed9381bca..73af78d3e2 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1,21 +1,19 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
// getchar.c: Code related to getting a character from the user or a script
// file, manipulations with redo buffer and stuff buffer.
#include <assert.h>
-#include <inttypes.h>
+#include <lauxlib.h>
+#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "lauxlib.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
@@ -24,11 +22,11 @@
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
-#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/gettext.h"
@@ -37,7 +35,7 @@
#include "nvim/insexpand.h"
#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
-#include "nvim/macros.h"
+#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/mapping.h"
#include "nvim/mbyte.h"
@@ -48,19 +46,18 @@
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
-#include "nvim/option.h"
+#include "nvim/option_vars.h"
#include "nvim/os/fileio.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/plines.h"
-#include "nvim/pos.h"
-#include "nvim/screen.h"
+#include "nvim/pos_defs.h"
#include "nvim/state.h"
#include "nvim/strings.h"
-#include "nvim/types.h"
+#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
/// Index in scriptin
static int curscript = 0;
@@ -85,61 +82,73 @@ static buffheader_T redobuff = { { NULL, { NUL } }, NULL, 0, 0 };
static buffheader_T old_redobuff = { { NULL, { NUL } }, NULL, 0, 0 };
static buffheader_T recordbuff = { { NULL, { NUL } }, NULL, 0, 0 };
-// First read ahead buffer. Used for translated commands.
+/// First read ahead buffer. Used for translated commands.
static buffheader_T readbuf1 = { { NULL, { NUL } }, NULL, 0, 0 };
-// Second read ahead buffer. Used for redo.
+/// Second read ahead buffer. Used for redo.
static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 };
-static int typeahead_char = 0; // typeahead char that's not flushed
+static int typeahead_char = 0; ///< typeahead char that's not flushed
-// when block_redo is true redo buffer will not be changed
-// used by edit() to repeat insertions and 'V' command for redoing
+/// When block_redo is true the redo buffer will not be changed.
+/// Used by edit() to repeat insertions.
static int block_redo = false;
-static int KeyNoremap = 0; // remapping flags
+static int KeyNoremap = 0; ///< remapping flags
-// Variables used by vgetorpeek() and flush_buffers()
-//
-// typebuf.tb_buf[] contains all characters that are not consumed yet.
-// typebuf.tb_buf[typebuf.tb_off] is the first valid character.
-// typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1] is the last valid char.
-// typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] must be NUL.
-// The head of the buffer may contain the result of mappings, abbreviations
-// and @a commands. The length of this part is typebuf.tb_maplen.
-// typebuf.tb_silent is the part where <silent> applies.
-// After the head are characters that come from the terminal.
-// typebuf.tb_no_abbr_cnt is the number of characters in typebuf.tb_buf that
-// should not be considered for abbreviations.
-// Some parts of typebuf.tb_buf may not be mapped. These parts are remembered
-// in typebuf.tb_noremap[], which is the same length as typebuf.tb_buf and
-// contains RM_NONE for the characters that are not to be remapped.
-// typebuf.tb_noremap[typebuf.tb_off] is the first valid flag.
-// (typebuf has been put in globals.h, because check_termcode() needs it).
-#define RM_YES 0 // tb_noremap: remap
-#define RM_NONE 1 // tb_noremap: don't remap
-#define RM_SCRIPT 2 // tb_noremap: remap local script mappings
-#define RM_ABBR 4 // tb_noremap: don't remap, do abbrev.
+/// Variables used by vgetorpeek() and flush_buffers()
+///
+/// typebuf.tb_buf[] contains all characters that are not consumed yet.
+/// typebuf.tb_buf[typebuf.tb_off] is the first valid character.
+/// typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1] is the last valid char.
+/// typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] must be NUL.
+/// The head of the buffer may contain the result of mappings, abbreviations
+/// and @a commands. The length of this part is typebuf.tb_maplen.
+/// typebuf.tb_silent is the part where <silent> applies.
+/// After the head are characters that come from the terminal.
+/// typebuf.tb_no_abbr_cnt is the number of characters in typebuf.tb_buf that
+/// should not be considered for abbreviations.
+/// Some parts of typebuf.tb_buf may not be mapped. These parts are remembered
+/// in typebuf.tb_noremap[], which is the same length as typebuf.tb_buf and
+/// contains RM_NONE for the characters that are not to be remapped.
+/// typebuf.tb_noremap[typebuf.tb_off] is the first valid flag.
+enum {
+ RM_YES = 0, ///< tb_noremap: remap
+ RM_NONE = 1, ///< tb_noremap: don't remap
+ RM_SCRIPT = 2, ///< tb_noremap: remap local script mappings
+ RM_ABBR = 4, ///< tb_noremap: don't remap, do abbrev.
+};
// typebuf.tb_buf has three parts: room in front (for result of mappings), the
// middle for typeahead and room for new characters (which needs to be 3 *
// MAXMAPLEN for the Amiga).
#define TYPELEN_INIT (5 * (MAXMAPLEN + 3))
-static char_u typebuf_init[TYPELEN_INIT]; // initial typebuf.tb_buf
-static char_u noremapbuf_init[TYPELEN_INIT]; // initial typebuf.tb_noremap
+static uint8_t typebuf_init[TYPELEN_INIT]; ///< initial typebuf.tb_buf
+static uint8_t noremapbuf_init[TYPELEN_INIT]; ///< initial typebuf.tb_noremap
-static size_t last_recorded_len = 0; // number of last recorded chars
+static size_t last_recorded_len = 0; ///< number of last recorded chars
+
+enum {
+ KEYLEN_PART_KEY = -1, ///< keylen value for incomplete key-code
+ KEYLEN_PART_MAP = -2, ///< keylen value for incomplete mapping
+};
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "getchar.c.generated.h"
#endif
-// Free and clear a buffer.
-void free_buff(buffheader_T *buf)
+static const char e_recursive_mapping[] = N_("E223: Recursive mapping");
+static const char e_cmd_mapping_must_end_with_cr[]
+ = N_("E1255: <Cmd> mapping must end with <CR>");
+static const char e_cmd_mapping_must_end_with_cr_before_second_cmd[]
+ = N_("E1136: <Cmd> mapping must end with <CR> before second <Cmd>");
+
+/// Free and clear a buffer.
+static void free_buff(buffheader_T *buf)
{
- buffblock_T *p, *np;
+ buffblock_T *np;
- for (p = buf->bh_first.b_next; p != NULL; p = np) {
+ for (buffblock_T *p = buf->bh_first.b_next; p != NULL; p = np) {
np = p->b_next;
xfree(p);
}
@@ -155,7 +164,6 @@ static char *get_buffcont(buffheader_T *buffer, int dozero)
{
size_t count = 0;
char *p = NULL;
- char *p2;
// compute the total length of the string
for (const buffblock_T *bp = buffer->bh_first.b_next;
@@ -163,9 +171,9 @@ static char *get_buffcont(buffheader_T *buffer, int dozero)
count += strlen(bp->b_str);
}
- if (count || dozero) {
+ if (count > 0 || dozero) {
p = xmalloc(count + 1);
- p2 = p;
+ char *p2 = p;
for (const buffblock_T *bp = buffer->bh_first.b_next;
bp != NULL; bp = bp->b_next) {
for (const char *str = bp->b_str; *str;) {
@@ -180,7 +188,7 @@ static char *get_buffcont(buffheader_T *buffer, int dozero)
/// Return the contents of the record buffer as a single string
/// and clear the record buffer.
/// K_SPECIAL in the returned string is escaped.
-char_u *get_recorded(void)
+char *get_recorded(void)
{
char *p;
size_t len;
@@ -202,7 +210,7 @@ char_u *get_recorded(void)
p[len - 1] = NUL;
}
- return (char_u *)p;
+ return p;
}
/// Return the contents of the redo buffer as a single string.
@@ -281,11 +289,11 @@ static void delete_buff_tail(buffheader_T *buf, int slen)
}
/// Add number "n" to buffer "buf".
-static void add_num_buff(buffheader_T *buf, long n)
+static void add_num_buff(buffheader_T *buf, int n)
{
char number[32];
- snprintf(number, sizeof(number), "%ld", n);
- add_buff(buf, number, -1L);
+ snprintf(number, sizeof(number), "%d", n);
+ add_buff(buf, number, -1);
}
/// Add character 'c' to buffer "buf".
@@ -317,7 +325,7 @@ static void add_char_buff(buffheader_T *buf, int c)
temp[0] = (char)c;
temp[1] = NUL;
}
- add_buff(buf, temp, -1L);
+ add_buff(buf, temp, -1);
}
}
@@ -338,14 +346,12 @@ static int read_readbuffers(int advance)
static int read_readbuf(buffheader_T *buf, int advance)
{
- char_u c;
-
if (buf->bh_first.b_next == NULL) { // buffer is empty
return NUL;
}
buffblock_T *const curr = buf->bh_first.b_next;
- c = (char_u)curr->b_str[buf->bh_index];
+ uint8_t c = (uint8_t)curr->b_str[buf->bh_index];
if (advance) {
if (curr->b_str[++buf->bh_index] == NUL) {
@@ -357,7 +363,7 @@ static int read_readbuf(buffheader_T *buf, int advance)
return c;
}
-// Prepare the read buffers for reading (if they contain something).
+/// Prepare the read buffers for reading (if they contain something).
static void start_stuff(void)
{
if (readbuf1.bh_first.b_next != NULL) {
@@ -385,15 +391,15 @@ int readbuf1_empty(void)
return (readbuf1.bh_first.b_next == NULL);
}
-// Set a typeahead character that won't be flushed.
+/// Set a typeahead character that won't be flushed.
void typeahead_noflush(int c)
{
typeahead_char = c;
}
-// Remove the contents of the stuff buffer and the mapped characters in the
-// typeahead buffer (used in case of an error). If "flush_typeahead" is true,
-// flush all typeahead characters (used when interrupted by a CTRL-C).
+/// Remove the contents of the stuff buffer and the mapped characters in the
+/// 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(flush_buffers_T flush_typeahead)
{
init_typebuf();
@@ -411,7 +417,7 @@ void flush_buffers(flush_buffers_T flush_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) != 0) {}
+ while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10) != 0) {}
}
typebuf.tb_off = MAXMAPLEN;
typebuf.tb_len = 0;
@@ -437,8 +443,8 @@ void beep_flush(void)
}
}
-// The previous contents of the redo buffer is kept in old_redobuffer.
-// This is used for the CTRL-O <.> command in insert mode.
+/// The previous contents of the redo buffer is kept in old_redobuffer.
+/// This is used for the CTRL-O <.> command in insert mode.
void ResetRedobuff(void)
{
if (block_redo) {
@@ -450,8 +456,8 @@ void ResetRedobuff(void)
redobuff.bh_first.b_next = NULL;
}
-// Discard the contents of the redo buffer and restore the previous redo
-// buffer.
+/// Discard the contents of the redo buffer and restore the previous redo
+/// buffer.
void CancelRedo(void)
{
if (block_redo) {
@@ -480,7 +486,7 @@ void saveRedobuff(save_redo_T *save_redo)
return;
}
- add_buff(&redobuff, s, -1L);
+ add_buff(&redobuff, s, -1);
xfree(s);
}
@@ -499,7 +505,7 @@ void restoreRedobuff(save_redo_T *save_redo)
void AppendToRedobuff(const char *s)
{
if (!block_redo) {
- add_buff(&redobuff, s, -1L);
+ add_buff(&redobuff, s, -1);
}
}
@@ -545,13 +551,32 @@ void AppendToRedobuffLit(const char *str, int len)
// CTRL-V '0' must be inserted as CTRL-V 048.
if (*s == NUL && c == '0') {
- add_buff(&redobuff, "048", 3L);
+ add_buff(&redobuff, "048", 3);
} else {
add_char_buff(&redobuff, c);
}
}
}
+/// Append "s" to the redo buffer, leaving 3-byte special key codes unmodified
+/// and escaping other K_SPECIAL bytes.
+void AppendToRedobuffSpec(const char *s)
+{
+ if (block_redo) {
+ return;
+ }
+
+ while (*s != NUL) {
+ if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
+ // Insert special key literally.
+ add_buff(&redobuff, s, 3);
+ s += 3;
+ } else {
+ add_char_buff(&redobuff, mb_cptr2char_adv(&s));
+ }
+ }
+}
+
/// Append a character to the redo buffer.
/// Translates special keys, NUL, K_SPECIAL and multibyte characters.
void AppendCharToRedobuff(int c)
@@ -562,7 +587,7 @@ void AppendCharToRedobuff(int c)
}
// Append a number to the redo buffer.
-void AppendNumberToRedobuff(long n)
+void AppendNumberToRedobuff(int n)
{
if (!block_redo) {
add_num_buff(&redobuff, n);
@@ -573,17 +598,17 @@ void AppendNumberToRedobuff(long n)
/// K_SPECIAL must already have been escaped.
void stuffReadbuff(const char *s)
{
- add_buff(&readbuf1, s, -1L);
+ add_buff(&readbuf1, s, -1);
}
/// Append string "s" to the redo stuff buffer.
/// @remark K_SPECIAL must already have been escaped.
void stuffRedoReadbuff(const char *s)
{
- add_buff(&readbuf2, s, -1L);
+ add_buff(&readbuf2, s, -1);
}
-void stuffReadbuffLen(const char *s, long len)
+void stuffReadbuffLen(const char *s, ptrdiff_t len)
{
add_buff(&readbuf1, s, len);
}
@@ -616,7 +641,7 @@ void stuffcharReadbuff(int c)
}
// Append a number to the stuff buffer.
-void stuffnumReadbuff(long n)
+void stuffnumReadbuff(int n)
{
add_num_buff(&readbuf1, n);
}
@@ -635,7 +660,7 @@ void stuffescaped(const char *arg, bool literally)
arg++;
}
if (arg > start) {
- stuffReadbuffLen(start, (arg - start));
+ stuffReadbuffLen(start, arg - start);
}
// stuff a single special character
@@ -658,18 +683,17 @@ void stuffescaped(const char *arg, bool literally)
static int read_redo(bool init, bool old_redo)
{
static buffblock_T *bp;
- static char_u *p;
+ static uint8_t *p;
int c;
int n;
- char_u buf[MB_MAXBYTES + 1];
- int i;
+ uint8_t buf[MB_MAXBYTES + 1];
if (init) {
bp = old_redo ? old_redobuff.bh_first.b_next : redobuff.bh_first.b_next;
if (bp == NULL) {
return FAIL;
}
- p = (char_u *)bp->b_str;
+ p = (uint8_t *)bp->b_str;
return OK;
}
if ((c = *p) == NUL) {
@@ -683,16 +707,16 @@ static int read_redo(bool init, bool old_redo)
} else {
n = 1;
}
- for (i = 0;; i++) {
+ for (int i = 0;; i++) {
if (c == K_SPECIAL) { // special key or escaped K_SPECIAL
c = TO_SPECIAL(p[1], p[2]);
p += 2;
}
if (*++p == NUL && bp->b_next != NULL) {
bp = bp->b_next;
- p = (char_u *)bp->b_str;
+ p = (uint8_t *)bp->b_str;
}
- buf[i] = (char_u)c;
+ buf[i] = (uint8_t)c;
if (i == n - 1) { // last byte of a character
if (n != 1) {
c = utf_ptr2char((char *)buf);
@@ -720,27 +744,25 @@ static void copy_redo(bool 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)
+/// 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(int count, bool 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);
+ int c = read_redo(false, old_redo);
// copy the buffer name, if present
if (c == '"') {
- add_buff(&readbuf2, "\"", 1L);
+ add_buff(&readbuf2, "\"", 1);
c = read_redo(false, old_redo);
// if a numbered buffer is used, increment the number
@@ -781,9 +803,10 @@ int start_redo(long count, bool old_redo)
return OK;
}
-// Repeat the last insert (R, o, O, a, A, i or I command) by stuffing
-// the redo buffer into readbuf2.
-// return FAIL for failure, OK otherwise
+/// Repeat the last insert (R, o, O, a, A, i or I command) by stuffing
+/// the redo buffer into readbuf2.
+///
+/// @return FAIL for failure, OK otherwise
int start_redo_ins(void)
{
int c;
@@ -797,7 +820,7 @@ int start_redo_ins(void)
while ((c = read_redo(false, false)) != NUL) {
if (vim_strchr("AaIiRrOo", c) != NULL) {
if (c == 'O' || c == 'o') {
- add_buff(&readbuf2, NL_STR, -1L);
+ add_buff(&readbuf2, NL_STR, -1);
}
break;
}
@@ -814,9 +837,9 @@ void stop_redo_ins(void)
block_redo = false;
}
-// Initialize typebuf.tb_buf to point to typebuf_init.
-// alloc() cannot be used here: In out-of-memory situations it would
-// be impossible to type anything.
+/// Initialize typebuf.tb_buf 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(void)
{
if (typebuf.tb_buf != NULL) {
@@ -837,28 +860,24 @@ bool noremap_keys(void)
return KeyNoremap & (RM_NONE|RM_SCRIPT);
}
-// Insert a string in position 'offset' in the typeahead buffer (for "@r"
-// and ":normal" command, vgetorpeek() and check_termcode())
-//
-// If noremap is REMAP_YES, new string can be mapped again.
-// If noremap is REMAP_NONE, new string cannot be mapped again.
-// If noremap is REMAP_SKIP, first char of new string cannot be mapped again,
-// but abbreviations are allowed.
-// If noremap is REMAP_SCRIPT, new string cannot be mapped again, except for
-// script-local mappings.
-// 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!).
-//
-// If silent is true, cmd_silent is set when the characters are obtained.
-//
-// return FAIL for failure, OK otherwise
+/// Insert a string in position "offset" in the typeahead buffer.
+///
+/// If "noremap" is REMAP_YES, new string can be mapped again.
+/// If "noremap" is REMAP_NONE, new string cannot be mapped again.
+/// If "noremap" is REMAP_SKIP, first char of new string cannot be mapped again,
+/// but abbreviations are allowed.
+/// If "noremap" is REMAP_SCRIPT, new string cannot be mapped again, except for
+/// script-local mappings.
+/// 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!).
+///
+/// If "silent" is true, cmd_silent is set when the characters are obtained.
+///
+/// @return FAIL for failure, OK otherwise
int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent)
{
- char_u *s1, *s2;
- int addlen;
- int i;
int val;
int nrm;
@@ -866,8 +885,9 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent)
if (++typebuf.tb_change_cnt == 0) {
typebuf.tb_change_cnt = 1;
}
+ state_no_longer_safe("ins_typebuf()");
- addlen = (int)strlen(str);
+ int addlen = (int)strlen(str);
if (offset == 0 && addlen <= typebuf.tb_off) {
// Easy case: there is room in front of typebuf.tb_buf[typebuf.tb_off]
@@ -893,8 +913,8 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent)
return FAIL;
}
int newlen = typebuf.tb_len + extra;
- s1 = xmalloc((size_t)newlen);
- s2 = xmalloc((size_t)newlen);
+ uint8_t *s1 = xmalloc((size_t)newlen);
+ uint8_t *s2 = xmalloc((size_t)newlen);
typebuf.tb_buflen = newlen;
// copy the old chars, before the insertion point
@@ -948,7 +968,7 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent)
} else {
nrm = noremap;
}
- for (i = 0; i < addlen; i++) {
+ for (int i = 0; i < addlen; i++) {
typebuf.tb_noremap[typebuf.tb_off + i + offset] =
(uint8_t)((--nrm >= 0) ? val : RM_YES);
}
@@ -978,11 +998,11 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent)
/// @return the length of what was inserted
int ins_char_typebuf(int c, int modifiers)
{
- char_u buf[MB_MAXBYTES * 3 + 4];
- unsigned int len = special_to_buf(c, modifiers, true, buf);
+ char buf[MB_MAXBYTES * 3 + 4];
+ unsigned len = special_to_buf(c, modifiers, true, buf);
assert(len < sizeof(buf));
buf[len] = NUL;
- (void)ins_typebuf((char *)buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
+ (void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
return (int)len;
}
@@ -1010,18 +1030,16 @@ int typebuf_typed(void)
return typebuf.tb_maplen == 0;
}
-// Return the number of characters that are mapped (or not typed).
+/// Get the number of characters that are mapped (or not typed).
int typebuf_maplen(void)
FUNC_ATTR_PURE
{
return typebuf.tb_maplen;
}
-// remove "len" characters from typebuf.tb_buf[typebuf.tb_off + offset]
+/// Remove "len" characters from typebuf.tb_buf[typebuf.tb_off + offset]
void del_typebuf(int len, int offset)
{
- int i;
-
if (len == 0) {
return; // nothing to do
}
@@ -1034,7 +1052,7 @@ void del_typebuf(int len, int offset)
typebuf.tb_off += len;
} else {
// Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[]
- i = typebuf.tb_off + offset;
+ int i = typebuf.tb_off + offset;
// Leave some extra room at the end to avoid reallocation.
if (typebuf.tb_off > MAXMAPLEN) {
memmove(typebuf.tb_buf + MAXMAPLEN,
@@ -1084,13 +1102,13 @@ void del_typebuf(int len, int offset)
}
}
-// Write typed characters to script file.
-// If recording is on put the character in the recordbuffer.
-static void gotchars(const char_u *chars, size_t len)
+/// Write typed characters to script file.
+/// If recording is on put the character in the recordbuffer.
+static void gotchars(const uint8_t *chars, size_t len)
FUNC_ATTR_NONNULL_ALL
{
- const char_u *s = chars;
- static char_u buf[4] = { 0 };
+ const uint8_t *s = chars;
+ static uint8_t buf[4] = { 0 };
static size_t buflen = 0;
size_t todo = len;
@@ -1130,6 +1148,13 @@ static void gotchars(const char_u *chars, size_t len)
maptick++;
}
+/// Record a <Nop> key.
+void gotchars_nop(void)
+{
+ uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_NOP };
+ gotchars(nop_buf, 3);
+}
+
/// Undo the last gotchars() for "len" bytes. To be used when putting a typed
/// character back into the typeahead buffer, thus gotchars() will be called
/// again.
@@ -1144,12 +1169,12 @@ void ungetchars(int len)
last_recorded_len -= (size_t)len;
}
-// 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.
+/// 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.
void may_sync_undo(void)
{
if ((!(State & (MODE_INSERT | MODE_CMDLINE)) || arrow_used)
@@ -1158,7 +1183,7 @@ void may_sync_undo(void)
}
}
-// Make "typebuf" empty and allocate new buffers.
+/// Make "typebuf" empty and allocate new buffers.
void alloc_typebuf(void)
{
typebuf.tb_buf = xmalloc(TYPELEN_INIT);
@@ -1174,7 +1199,7 @@ void alloc_typebuf(void)
}
}
-// Free the buffers of "typebuf".
+/// Free the buffers of "typebuf".
void free_typebuf(void)
{
if (typebuf.tb_buf == typebuf_init) {
@@ -1189,8 +1214,8 @@ void free_typebuf(void)
}
}
-// When doing ":so! file", the current typeahead needs to be saved, and
-// restored when "file" has been read completely.
+/// When doing ":so! file", the current typeahead needs to be saved, and
+/// restored when "file" has been read completely.
static typebuf_T saved_typebuf[NSCRIPT];
void save_typebuf(void)
@@ -1200,12 +1225,12 @@ void save_typebuf(void)
alloc_typebuf();
}
-static int old_char = -1; // character put back by vungetc()
-static int old_mod_mask; // mod_mask for ungotten character
-static int old_mouse_grid; // mouse_grid related to old_char
-static int old_mouse_row; // mouse_row related to old_char
-static int old_mouse_col; // mouse_col related to old_char
-static int old_KeyStuffed; // whether old_char was stuffed
+static int old_char = -1; ///< character put back by vungetc()
+static int old_mod_mask; ///< mod_mask for ungotten character
+static int old_mouse_grid; ///< mouse_grid related to old_char
+static int old_mouse_row; ///< mouse_row related to old_char
+static int old_mouse_col; ///< mouse_col related to old_char
+static int old_KeyStuffed; ///< whether old_char was stuffed
static bool can_get_old_char(void)
{
@@ -1214,7 +1239,7 @@ static bool can_get_old_char(void)
return old_char != -1 && (old_KeyStuffed || stuff_empty());
}
-// Save all three kinds of typeahead, so that the user must type at a prompt.
+/// Save all three kinds of typeahead, so that the user must type at a prompt.
void save_typeahead(tasave_T *tp)
{
tp->save_typebuf = typebuf;
@@ -1230,8 +1255,8 @@ void save_typeahead(tasave_T *tp)
readbuf2.bh_first.b_next = NULL;
}
-// Restore the typeahead to what it was before calling save_typeahead().
-// The allocated memory is freed, can only be called once!
+/// Restore the typeahead to what it was before calling save_typeahead().
+/// The allocated memory is freed, can only be called once!
void restore_typeahead(tasave_T *tp)
{
if (tp->typebuf_valid) {
@@ -1317,7 +1342,7 @@ void openscript(char *name, bool directly)
}
}
-// Close the currently active input script.
+/// Close the currently active input script.
static void closescript(void)
{
free_typebuf();
@@ -1357,8 +1382,8 @@ void before_blocking(void)
}
}
-/// updatescript() is called when a character can be written to the script file
-/// or when we have waited some time for a character (c == 0).
+/// updatescript() is called when a character can be written to 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.
@@ -1408,10 +1433,8 @@ int merge_modifiers(int c_arg, int *modifiers)
/// Returns the modifiers in the global "mod_mask".
int vgetc(void)
{
- int c, c2;
- int n;
- char_u buf[MB_MAXBYTES + 1];
- int i;
+ int c;
+ uint8_t buf[MB_MAXBYTES + 1];
// Do garbage collection when garbagecollect() was called previously and
// we are now at the toplevel.
@@ -1429,6 +1452,8 @@ int vgetc(void)
mouse_row = old_mouse_row;
mouse_col = old_mouse_col;
} else {
+ int c2;
+ int n;
// number of characters recorded from the last vgetc() call
static size_t last_vgetc_recorded_len = 0;
@@ -1440,7 +1465,7 @@ int vgetc(void)
// if peeking records more
last_recorded_len -= last_vgetc_recorded_len;
- for (;;) { // this is done twice if there are modifiers
+ while (true) { // this is done twice if there are modifiers
bool did_inc = false;
if (mod_mask) { // no mapping after modifier has been read
no_mapping++;
@@ -1553,9 +1578,9 @@ int vgetc(void)
// Note: This will loop until enough bytes are received!
if ((n = MB_BYTE2LEN_CHECK(c)) > 1) {
no_mapping++;
- buf[0] = (char_u)c;
- for (i = 1; i < n; i++) {
- buf[i] = (char_u)vgetorpeek(true);
+ buf[0] = (uint8_t)c;
+ for (int i = 1; i < n; i++) {
+ buf[i] = (uint8_t)vgetorpeek(true);
if (buf[i] == K_SPECIAL) {
// Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence,
// which represents a K_SPECIAL (0x80).
@@ -1601,11 +1626,17 @@ int vgetc(void)
// Execute Lua on_key callbacks.
nlua_execute_on_key(c);
+ // Need to process the character before we know it's safe to do something
+ // else.
+ if (c != K_IGNORE) {
+ state_no_longer_safe("key typed");
+ }
+
return c;
}
-// Like vgetc(), but never return a NUL when called recursively, get a key
-// directly from the user (ignoring typeahead).
+/// Like vgetc(), but never return a NUL when called recursively, get a key
+/// directly from the user (ignoring typeahead).
int safe_vgetc(void)
{
int c;
@@ -1617,8 +1648,8 @@ int safe_vgetc(void)
return c;
}
-// Like safe_vgetc(), but loop to handle K_IGNORE.
-// Also ignore scrollbar events.
+/// Like safe_vgetc(), but loop to handle K_IGNORE.
+/// Also ignore scrollbar events.
int plain_vgetc(void)
{
int c;
@@ -1631,10 +1662,10 @@ int plain_vgetc(void)
return c;
}
-// 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.
+/// 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)
{
if (can_get_old_char()) {
@@ -1643,9 +1674,9 @@ int vpeekc(void)
return vgetorpeek(false);
}
-// Check if any character is available, also half an escape sequence.
-// Trick: when no typeahead found, but there is something in the typeahead
-// buffer, it must be an ESC that is recognized as the start of a key code.
+/// Check if any character is available, also half an escape sequence.
+/// Trick: when no typeahead found, but there is something in the typeahead
+/// buffer, it must be an ESC that is recognized as the start of a key code.
int vpeekc_any(void)
{
int c;
@@ -1657,9 +1688,9 @@ int vpeekc_any(void)
return c;
}
-// Call vpeekc() without causing anything to be mapped.
-// Return true if a character is available, false otherwise.
-int char_avail(void)
+/// Call vpeekc() without causing anything to be mapped.
+/// @return true if a character is available, false otherwise.
+bool char_avail(void)
{
int retval;
@@ -1678,7 +1709,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
no_mapping++;
allow_keys++;
- for (;;) {
+ while (true) {
if (msg_col > 0) {
// Position the cursor. Needed after a message that ends in a space.
ui_cursor_goto(msg_row, msg_col);
@@ -1688,7 +1719,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
// getchar(): blocking wait.
// TODO(bfredl): deduplicate shared logic with state_enter ?
if (!char_avail()) {
- // flush output before waiting
+ // Flush screen updates before blocking.
ui_flush();
(void)os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
if (!multiqueue_empty(main_loop.events)) {
@@ -1754,9 +1785,9 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
int grid = mouse_grid;
linenr_T lnum;
win_T *wp;
- int winnr = 1;
if (row >= 0 && col >= 0) {
+ int winnr = 1;
// Find the window at the mouse coordinates and compute the
// text position.
win_T *const win = mouse_find_win(&grid, &row, &col);
@@ -1796,7 +1827,7 @@ void f_getcharstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int i = 0;
if (n != 0) {
- i += utf_char2bytes((int)n, (char *)temp);
+ i += utf_char2bytes((int)n, temp);
}
assert(i < 7);
temp[i++] = NUL;
@@ -1820,7 +1851,7 @@ typedef enum {
/// Put "string[new_slen]" in typebuf.
/// Remove "slen" bytes.
/// @return FAIL for error, OK otherwise.
-static int put_string_in_typebuf(int offset, int slen, char_u *string, int new_slen)
+static int put_string_in_typebuf(int offset, int slen, uint8_t *string, int new_slen)
{
int extra = new_slen - slen;
string[new_slen] = NUL;
@@ -1843,7 +1874,7 @@ static int put_string_in_typebuf(int offset, int slen, char_u *string, int new_s
/// in Insert mode completion. This includes the form with a CTRL modifier.
static bool at_ins_compl_key(void)
{
- char_u *p = typebuf.tb_buf + typebuf.tb_off;
+ uint8_t *p = typebuf.tb_buf + typebuf.tb_off;
int c = *p;
if (typebuf.tb_len > 3 && c == K_SPECIAL && p[1] == KS_MODIFIER && (p[2] & MOD_MASK_CTRL)) {
@@ -1863,7 +1894,7 @@ static int check_simplify_modifier(int max_offset)
if (offset + 3 >= typebuf.tb_len) {
break;
}
- char_u *tp = typebuf.tb_buf + typebuf.tb_off + offset;
+ uint8_t *tp = typebuf.tb_buf + typebuf.tb_off + offset;
if (tp[0] == K_SPECIAL && tp[1] == KS_MODIFIER) {
// A modifier was not used for a mapping, apply it to ASCII
// keys. Shift would already have been applied.
@@ -1879,12 +1910,12 @@ static int check_simplify_modifier(int max_offset)
vgetc_char = c;
vgetc_mod_mask = tp[2];
}
- char_u new_string[MB_MAXBYTES];
+ uint8_t new_string[MB_MAXBYTES];
int len;
if (IS_SPECIAL(new_c)) {
new_string[0] = K_SPECIAL;
- new_string[1] = (char_u)K_SECOND(new_c);
- new_string[2] = (char_u)K_THIRD(new_c);
+ new_string[1] = (uint8_t)K_SECOND(new_c);
+ new_string[2] = (uint8_t)K_THIRD(new_c);
len = 3;
} else {
len = utf_char2bytes(new_c, (char *)new_string);
@@ -1894,7 +1925,7 @@ static int check_simplify_modifier(int max_offset)
return -1;
}
} else {
- tp[2] = (char_u)modifier;
+ tp[2] = (uint8_t)modifier;
if (put_string_in_typebuf(offset + 3, 1, new_string, len) == FAIL) {
return -1;
}
@@ -1920,10 +1951,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
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();
bool is_plug_map = false;
@@ -1956,6 +1984,8 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
&& State != MODE_ASKMORE
&& State != MODE_CONFIRM
&& !at_ins_compl_key()) {
+ int mlen;
+ int nolmaplen;
if (tb_c1 == K_SPECIAL) {
nolmaplen = 2;
} else {
@@ -2016,10 +2046,10 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
// 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 = (char_u *)mp->m_keys;
- char_u *p2 = (char_u *)mb_unescape((const char **)&p1);
+ const char *p1 = mp->m_keys;
+ const char *p2 = mb_unescape(&p1);
- if (p2 != NULL && MB_BYTE2LEN(tb_c1) > utfc_ptr2len((char *)p2)) {
+ if (p2 != NULL && MB_BYTE2LEN(tb_c1) > utfc_ptr2len(p2)) {
mlen = 0;
}
@@ -2081,39 +2111,6 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
}
}
- // Check for match with 'pastetoggle'
- if (*p_pt != NUL && mp == NULL && (State & (MODE_INSERT | MODE_NORMAL))) {
- bool match = typebuf_match_len((char_u *)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_give_err("paste", !p_paste, NULL, 0);
- if (!(State & MODE_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) {
// When no matching mapping found or found a non-matching mapping that
// matches at least what the matching mapping matched:
@@ -2124,13 +2121,6 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
|| (typebuf.tb_buf[typebuf.tb_off + 1] == KS_MODIFIER && typebuf.tb_len < 4))) {
// Incomplete modifier sequence: cannot decide whether to simplify yet.
keylen = KEYLEN_PART_KEY;
- } else if (keylen == KEYLEN_PART_KEY && !*timedout) {
- // If 'pastetoggle' matched partially, don't simplify.
- // When the last characters were not typed, don't wait for a typed character to
- // complete 'pastetoggle'.
- if (typebuf.tb_len == typebuf.tb_maplen) {
- keylen = 0;
- }
} else {
// Try to include the modifier into the key.
keylen = check_simplify_modifier(max_mlen + 1);
@@ -2168,6 +2158,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
// complete match
if (keylen >= 0 && keylen <= typebuf.tb_len) {
+ int i;
char *map_str = NULL;
// Write chars to script file(s).
@@ -2183,7 +2174,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
// 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"));
+ emsg(_(e_recursive_mapping));
if (State & MODE_CMDLINE) {
redrawcmdline();
} else {
@@ -2199,7 +2190,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
// mode temporarily. Append K_SELECT to switch back to Select mode.
if (VIsual_active && VIsual_select && (mp->m_mode & MODE_VISUAL)) {
VIsual_select = false;
- (void)ins_typebuf((char *)K_SELECT_STRING, REMAP_NONE, 0, true, false);
+ (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE, 0, true, false);
}
// Copy the values from *mp that are used, because evaluating the
@@ -2218,9 +2209,6 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
if (mp->m_expr) {
const int save_vgetc_busy = vgetc_busy;
const bool save_may_garbage_collect = may_garbage_collect;
- const int save_cursor_row = ui_current_row();
- const int save_cursor_col = ui_current_col();
- const handle_T save_cursor_grid = ui_cursor_grid();
const int prev_did_emsg = did_emsg;
vgetc_busy = 0;
@@ -2232,28 +2220,28 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
}
map_str = eval_map_expr(mp, NUL);
- // The mapping may do anything, but we expect it to take care of
- // redrawing. Do put the cursor back where it was.
- ui_grid_cursor_goto(save_cursor_grid, save_cursor_row, save_cursor_col);
- ui_flush();
-
- // If an error was displayed and the expression returns an empty
- // string, generate a <Nop> to allow for a redraw.
- if (prev_did_emsg != did_emsg && (map_str == NULL || *map_str == NUL)) {
- char buf[4];
- xfree(map_str);
- buf[0] = (char)K_SPECIAL;
- buf[1] = (char)KS_EXTRA;
- buf[2] = KE_IGNORE;
- buf[3] = NUL;
- map_str = xstrdup(buf);
- if (State & MODE_CMDLINE) {
- // redraw the command below the error
- msg_didout = true;
- if (msg_row < cmdline_row) {
- msg_row = cmdline_row;
+ if ((map_str == NULL || *map_str == NUL)) {
+ // If an error was displayed and the expression returns an empty
+ // string, generate a <Nop> to allow for a redraw.
+ if (prev_did_emsg != did_emsg) {
+ char buf[4];
+ xfree(map_str);
+ buf[0] = (char)K_SPECIAL;
+ buf[1] = (char)KS_EXTRA;
+ buf[2] = KE_IGNORE;
+ buf[3] = NUL;
+ map_str = xstrdup(buf);
+ if (State & MODE_CMDLINE) {
+ // redraw the command below the error
+ msg_didout = true;
+ if (msg_row < cmdline_row) {
+ msg_row = cmdline_row;
+ }
+ redrawcmd();
}
- redrawcmd();
+ } else if (State & (MODE_NORMAL | MODE_INSERT)) {
+ // otherwise, just put back the cursor
+ setcursor();
}
}
@@ -2275,7 +2263,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
// 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 & MODE_LANGMAP) != 0) {
- gotchars((char_u *)map_str, strlen(map_str));
+ gotchars((uint8_t *)map_str, strlen(map_str));
}
if (save_m_noremap != REMAP_YES) {
@@ -2355,16 +2343,12 @@ void check_end_reg_executing(bool advance)
/// K_SPECIAL may be escaped, need to get two more bytes then.
static int vgetorpeek(bool advance)
{
- int c, c1;
+ int c;
bool timedout = false; // waited for more than 'timeoutlen'
// for mapping to complete or
// 'ttimeoutlen' for complete key code
int mapdepth = 0; // check for recursive mapping
bool mode_deleted = false; // set when mode has been deleted
- int new_wcol, new_wrow;
- int n;
- 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:
@@ -2414,7 +2398,7 @@ static int vgetorpeek(bool advance)
// 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 (;;) {
+ while (true) {
check_end_reg_executing(advance);
// os_breakcheck() is slow, don't use it too often when
// inside a mapping. But call it each time for typed
@@ -2432,7 +2416,7 @@ static int vgetorpeek(bool advance)
int keylen = 0;
if (got_int) {
// flush all input
- c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L);
+ c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0);
// If inchar() returns true (script file was active) or we
// are inside a mapping, get out of Insert mode.
@@ -2450,7 +2434,7 @@ static int vgetorpeek(bool advance)
if (advance) {
// Also record this character, it might be needed to
// get out of Insert mode.
- *typebuf.tb_buf = (char_u)c;
+ *typebuf.tb_buf = (uint8_t)c;
gotchars(typebuf.tb_buf, 1);
}
cmd_silent = false;
@@ -2501,8 +2485,8 @@ static int vgetorpeek(bool advance)
// 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;
+ int new_wcol = curwin->w_wcol;
+ int new_wrow = curwin->w_wrow;
if (advance
&& typebuf.tb_len == 1
&& typebuf.tb_buf[typebuf.tb_off] == ESC
@@ -2511,20 +2495,19 @@ static int vgetorpeek(bool advance)
&& typebuf.tb_maplen == 0
&& (State & MODE_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;
- char_u *ptr;
-
+ && (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len, 3, 25)) == 0) {
if (mode_displayed) {
unshowmode(true);
mode_deleted = true;
}
validate_cursor();
- old_wcol = curwin->w_wcol;
- old_wrow = curwin->w_wrow;
+ int old_wcol = curwin->w_wcol;
+ int old_wrow = curwin->w_wrow;
// move cursor left, if possible
if (curwin->w_cursor.col != 0) {
+ colnr_T col = 0;
+ char *ptr;
if (curwin->w_wcol > 0) {
// After auto-indenting and no text is following,
// we are expecting to truncate the trailing
@@ -2533,11 +2516,10 @@ static int vgetorpeek(bool advance)
if (did_ai
&& *skipwhite(get_cursor_line_ptr() + curwin->w_cursor.col) == NUL) {
curwin->w_wcol = 0;
- ptr = (char_u *)get_cursor_line_ptr();
+ ptr = get_cursor_line_ptr();
chartabsize_T cts;
- init_chartabsize_arg(&cts, curwin,
- curwin->w_cursor.lnum, 0, (char *)ptr, (char *)ptr);
- while ((char_u *)cts.cts_ptr < ptr + curwin->w_cursor.col) {
+ init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0, ptr, ptr);
+ while (cts.cts_ptr < ptr + curwin->w_cursor.col) {
if (!ascii_iswhite(*cts.cts_ptr)) {
curwin->w_wcol = cts.cts_vcol;
}
@@ -2563,9 +2545,9 @@ static int vgetorpeek(bool advance)
if (col > 0 && curwin->w_wcol > 0) {
// Correct when the cursor is on the right halve
// of a double-wide character.
- ptr = (char_u *)get_cursor_line_ptr();
- col -= utf_head_off((char *)ptr, (char *)ptr + col);
- if (utf_ptr2cells((char *)ptr + col) > 1) {
+ ptr = get_cursor_line_ptr();
+ col -= utf_head_off(ptr, ptr + col);
+ if (utf_ptr2cells(ptr + col) > 1) {
curwin->w_wcol--;
}
}
@@ -2583,7 +2565,7 @@ static int vgetorpeek(bool advance)
// Allow mapping for just typed characters. When we get here c
// is the number of extra bytes and typebuf.tb_len is 1.
- for (n = 1; n <= c; n++) {
+ for (int n = 1; n <= c; n++) {
typebuf.tb_noremap[typebuf.tb_off + n] = RM_YES;
}
typebuf.tb_len += c;
@@ -2651,7 +2633,7 @@ static int vgetorpeek(bool advance)
// input from the user), show the partially matched characters
// to the user with showcmd.
int showcmd_idx = 0;
- c1 = 0;
+ bool showing_partial = false;
if (typebuf.tb_len > 0 && advance && !exmode_active) {
if (((State & (MODE_NORMAL | MODE_INSERT)) || State == MODE_LANGMAP)
&& State != MODE_HITRETURN) {
@@ -2660,11 +2642,11 @@ static int vgetorpeek(bool advance)
&& ptr2cells((char *)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;
+ showing_partial = true;
}
// need to use the col and row from above here
- old_wcol = curwin->w_wcol;
- old_wrow = curwin->w_wrow;
+ int old_wcol = curwin->w_wcol;
+ int old_wrow = curwin->w_wrow;
curwin->w_wcol = new_wcol;
curwin->w_wrow = new_wrow;
push_showcmd();
@@ -2678,12 +2660,15 @@ static int vgetorpeek(bool advance)
curwin->w_wrow = old_wrow;
}
- // this looks nice when typing a dead character map
- if ((State & MODE_CMDLINE) && cmdline_star == 0) {
+ // This looks nice when typing a dead character map.
+ // There is no actual command line for get_number().
+ if ((State & MODE_CMDLINE)
+ && get_cmdline_info()->cmdbuff != NULL
+ && cmdline_star == 0) {
char *p = (char *)typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len - 1;
if (ptr2cells(p) == 1 && (uint8_t)(*p) < 128) {
putcmdline(*p, false);
- c1 = 1;
+ showing_partial = true;
}
}
}
@@ -2695,20 +2680,20 @@ static int vgetorpeek(bool advance)
timedout = false;
}
- long wait_time = 0;
+ int wait_time = 0;
if (advance) {
if (typebuf.tb_len == 0 || !(p_timeout || (p_ttimeout && keylen == KEYLEN_PART_KEY))) {
// blocking wait
- wait_time = -1L;
+ wait_time = -1;
} else if (keylen == KEYLEN_PART_KEY && p_ttm >= 0) {
- wait_time = p_ttm;
+ wait_time = (int)p_ttm;
} else {
- wait_time = p_tm;
+ wait_time = (int)p_tm;
}
}
- wait_tb_len = typebuf.tb_len;
+ int 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,
wait_time);
@@ -2716,11 +2701,12 @@ static int vgetorpeek(bool advance)
if (showcmd_idx != 0) {
pop_showcmd();
}
- if (c1 == 1) {
+ if (showing_partial == 1) {
if (State & MODE_INSERT) {
edit_unputchar();
}
- if (State & MODE_CMDLINE) {
+ if ((State & MODE_CMDLINE)
+ && get_cmdline_info()->cmdbuff != NULL) {
unputcmdline();
} else {
setcursor(); // put cursor back where it belongs
@@ -2743,7 +2729,7 @@ static int vgetorpeek(bool advance)
typebuf.tb_noremap[typebuf.tb_off + typebuf.tb_len++] = RM_YES;
}
}
- } // for (;;)
+ } // while (true)
} // if (!character from stuffbuf)
// if advance is false don't loop on NULs
@@ -2769,14 +2755,9 @@ static int vgetorpeek(bool advance)
}
if (timedout && c == ESC) {
- char_u nop_buf[3];
-
// When recording there will be no timeout. Add a <Nop> after the ESC
// to avoid that it forms a key code with following characters.
- nop_buf[0] = K_SPECIAL;
- nop_buf[1] = KS_EXTRA;
- nop_buf[2] = KE_NOP;
- gotchars(nop_buf, 3);
+ gotchars_nop();
}
vgetc_busy--;
@@ -2807,13 +2788,13 @@ static int vgetorpeek(bool advance)
/// Return -1 when end of input script reached.
///
/// @param wait_time milliseconds
-int inchar(char_u *buf, int maxlen, long wait_time)
+int inchar(uint8_t *buf, int maxlen, long wait_time)
{
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) {
+ if (wait_time == -1 || wait_time > 100) {
// flush output before waiting
ui_flush();
}
@@ -2846,7 +2827,7 @@ int inchar(char_u *buf, int maxlen, long wait_time)
return -1;
}
} else {
- buf[0] = (char_u)script_char;
+ buf[0] = (uint8_t)script_char;
len = 1;
}
}
@@ -2860,10 +2841,10 @@ int inchar(char_u *buf, int maxlen, long wait_time)
// and buf may be pointing inside typebuf.tb_buf[].
if (got_int) {
#define DUM_LEN (MAXMAPLEN * 3 + 3)
- char_u dum[DUM_LEN + 1];
+ uint8_t dum[DUM_LEN + 1];
- for (;;) {
- len = os_inchar(dum, DUM_LEN, 0L, 0, NULL);
+ while (true) {
+ len = os_inchar(dum, DUM_LEN, 0, 0, NULL);
if (len == 0 || (len == 1 && dum[0] == Ctrl_C)) {
break;
}
@@ -2872,8 +2853,10 @@ int inchar(char_u *buf, int maxlen, long wait_time)
}
// Always flush the output characters when getting input characters
- // from the user.
- ui_flush();
+ // from the user and not just peeking.
+ if (wait_time == -1 || wait_time > 10) {
+ ui_flush();
+ }
// Fill up to a third of the buffer, because each character may be
// tripled below.
@@ -2896,10 +2879,10 @@ int inchar(char_u *buf, int maxlen, long wait_time)
return fix_input_buffer(buf, len);
}
-// Fix typed characters for use by vgetc() and check_termcode().
-// "buf[]" must have room to triple the number of bytes!
-// Returns the new length.
-int fix_input_buffer(char_u *buf, int len)
+/// Fix typed characters for use by vgetc().
+/// "buf[]" must have room to triple the number of bytes!
+/// Returns the new length.
+int fix_input_buffer(uint8_t *buf, int len)
FUNC_ATTR_NONNULL_ALL
{
if (!using_script()) {
@@ -2910,19 +2893,18 @@ int fix_input_buffer(char_u *buf, int len)
}
// Reading from script, need to process special bytes
- int i;
- char_u *p = buf;
+ uint8_t *p = buf;
// Two characters are special: NUL and K_SPECIAL.
// Replace NUL by K_SPECIAL KS_ZERO KE_FILLER
// Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER
- for (i = len; --i >= 0; p++) {
+ for (int i = len; --i >= 0; p++) {
if (p[0] == NUL
|| (p[0] == K_SPECIAL
&& (i < 2 || p[1] != KS_EXTRA))) {
memmove(p + 3, p + 1, (size_t)i);
- p[2] = (char_u)K_THIRD(p[0]);
- p[1] = (char_u)K_SECOND(p[0]);
+ p[2] = (uint8_t)K_THIRD(p[0]);
+ p[1] = (uint8_t)K_SECOND(p[0]);
p[0] = K_SPECIAL;
p += 2;
len += 2;
@@ -2932,28 +2914,19 @@ int fix_input_buffer(char_u *buf, int len)
return len;
}
-static bool typebuf_match_len(const uint8_t *str, int *mlen)
-{
- int i;
- for (i = 0; i < typebuf.tb_len && str[i]; i++) {
- if (str[i] != typebuf.tb_buf[typebuf.tb_off + i]) {
- break;
- }
- }
- *mlen = i;
- return str[i] == NUL; // matched the whole string
-}
-
-/// Get command argument for <Cmd> key
+/// Function passed to do_cmdline() to get the command after a <Cmd> key from
+/// typeahead.
char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
{
garray_T line_ga;
- int c1 = -1, c2;
+ int c1 = -1;
+ int c2;
int cmod = 0;
bool aborted = false;
ga_init(&line_ga, 1, 32);
+ // no mapping for these characters
no_mapping++;
got_int = false;
@@ -2963,16 +2936,17 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
if (vgetorpeek(false) == NUL) {
// incomplete <Cmd> is an error, because there is not much the user
// could do in this state.
- emsg(e_cmdmap_err);
+ emsg(_(e_cmd_mapping_must_end_with_cr));
aborted = true;
break;
}
// Get one character at a time.
c1 = vgetorpeek(true);
+
// Get two extra bytes for special keys
if (c1 == K_SPECIAL) {
- c1 = vgetorpeek(true); // no mapping for these chars
+ c1 = vgetorpeek(true);
c2 = vgetorpeek(true);
if (c1 == KS_MODIFIER) {
cmod = c2;
@@ -2988,8 +2962,8 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
} else if (c1 == ESC) {
aborted = true;
} else if (c1 == K_COMMAND) {
- // special case to give nicer error message
- emsg(e_cmdmap_repeated);
+ // give a nicer error message for this special case
+ emsg(_(e_cmd_mapping_must_end_with_cr_before_second_cmd));
aborted = true;
} else if (c1 == K_SNR) {
ga_concat(&line_ga, "<SNR>");
@@ -3020,7 +2994,12 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
return line_ga.ga_data;
}
-bool map_execute_lua(void)
+/// Handle a Lua mapping: get its LuaRef from typeahead and execute it.
+///
+/// @param may_repeat save the LuaRef for redoing with "." later
+///
+/// @return false if getting the LuaRef was aborted, true otherwise
+bool map_execute_lua(bool may_repeat)
{
garray_T line_ga;
int c1 = -1;
@@ -3052,6 +3031,10 @@ bool map_execute_lua(void)
}
LuaRef ref = (LuaRef)atoi(line_ga.ga_data);
+ if (may_repeat) {
+ repeat_luaref = ref;
+ }
+
Error err = ERROR_INIT;
Array args = ARRAY_DICT_INIT;
nlua_call_ref(ref, NULL, args, false, &err);