diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
commit | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch) | |
tree | cd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/getchar.c | |
parent | eaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.gz rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.tar.bz2 rneovim-1b7b916b7631ddf73c38e3a0070d64e4636cb2f3.zip |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/getchar.c')
-rw-r--r-- | src/nvim/getchar.c | 683 |
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); |