diff options
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; } |