diff options
Diffstat (limited to 'src/nvim/getchar.c')
-rw-r--r-- | src/nvim/getchar.c | 501 |
1 files changed, 232 insertions, 269 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 0a9457ef35..b9e3b6b902 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -7,11 +7,15 @@ #include <assert.h> #include <inttypes.h> #include <stdbool.h> +#include <stddef.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/assert.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cursor.h" @@ -19,16 +23,21 @@ #include "nvim/edit.h" #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/garray.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" #include "nvim/input.h" #include "nvim/insexpand.h" #include "nvim/keycodes.h" #include "nvim/lua/executor.h" +#include "nvim/macros.h" #include "nvim/main.h" #include "nvim/mapping.h" #include "nvim/mbyte.h" @@ -44,8 +53,11 @@ #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/plines.h" +#include "nvim/pos.h" +#include "nvim/screen.h" #include "nvim/state.h" #include "nvim/strings.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/vim.h" @@ -87,25 +99,23 @@ static int block_redo = false; 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). - */ +// 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 @@ -124,9 +134,7 @@ static size_t last_recorded_len = 0; // number of last recorded chars # include "getchar.c.generated.h" #endif -/* - * Free and clear a buffer. - */ +// Free and clear a buffer. void free_buff(buffheader_T *buf) { buffblock_T *p, *np; @@ -152,7 +160,7 @@ static char_u *get_buffcont(buffheader_T *buffer, int dozero) // compute the total length of the string for (const buffblock_T *bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) { - count += STRLEN(bp->b_str); + count += strlen(bp->b_str); } if (count || dozero) { @@ -174,31 +182,27 @@ static char_u *get_buffcont(buffheader_T *buffer, int dozero) /// K_SPECIAL in the returned string is escaped. char_u *get_recorded(void) { - char_u *p; + char *p; size_t len; - p = get_buffcont(&recordbuff, true); + p = (char *)get_buffcont(&recordbuff, true); free_buff(&recordbuff); - /* - * Remove the characters that were added the last time, these must be the - * (possibly mapped) characters that stopped the recording. - */ - len = STRLEN(p); + // Remove the characters that were added the last time, these must be the + // (possibly mapped) characters that stopped the recording. + len = strlen(p); if (len >= last_recorded_len) { len -= last_recorded_len; p[len] = NUL; } - /* - * When stopping recording from Insert mode with CTRL-O q, also remove the - * CTRL-O. - */ + // When stopping recording from Insert mode with CTRL-O q, also remove the + // CTRL-O. if (len > 0 && restart_edit != 0 && p[len - 1] == Ctrl_O) { p[len - 1] = NUL; } - return p; + return (char_u *)p; } /// Return the contents of the redo buffer as a single string. @@ -233,14 +237,14 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle } else if (buf->bh_index != 0) { memmove(buf->bh_first.b_next->b_str, buf->bh_first.b_next->b_str + buf->bh_index, - STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1); + strlen(buf->bh_first.b_next->b_str + buf->bh_index) + 1); } buf->bh_index = 0; size_t len; if (buf->bh_space >= (size_t)slen) { - len = STRLEN(buf->bh_curr->b_str); - STRLCPY(buf->bh_curr->b_str + len, s, slen + 1); + len = strlen(buf->bh_curr->b_str); + xstrlcpy(buf->bh_curr->b_str + len, s, (size_t)slen + 1); buf->bh_space -= (size_t)slen; } else { if (slen < MINIMAL_SIZE) { @@ -250,7 +254,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle } buffblock_T *p = xmalloc(sizeof(buffblock_T) + len); buf->bh_space = len - (size_t)slen; - STRLCPY(p->b_str, s, slen + 1); + xstrlcpy(p->b_str, s, (size_t)slen + 1); p->b_next = buf->bh_curr->b_next; buf->bh_curr->b_next = p; @@ -267,11 +271,13 @@ static void delete_buff_tail(buffheader_T *buf, int slen) if (buf->bh_curr == NULL) { return; // nothing to delete } - len = (int)STRLEN(buf->bh_curr->b_str); - if (len >= slen) { - buf->bh_curr->b_str[len - slen] = NUL; - buf->bh_space += (size_t)slen; + len = (int)strlen(buf->bh_curr->b_str); + if (len < slen) { + return; } + + buf->bh_curr->b_str[len - slen] = NUL; + buf->bh_space += (size_t)slen; } /// Add number "n" to buffer "buf". @@ -351,9 +357,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) { @@ -381,19 +385,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(); @@ -437,32 +437,32 @@ 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) { - free_buff(&old_redobuff); - old_redobuff = redobuff; - redobuff.bh_first.b_next = NULL; + if (block_redo) { + return; } + + free_buff(&old_redobuff); + old_redobuff = redobuff; + 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) { - free_buff(&redobuff); - redobuff = old_redobuff; - old_redobuff.bh_first.b_next = NULL; - start_stuff(); - while (read_readbuffers(true) != NUL) {} + if (block_redo) { + return; } + + free_buff(&redobuff); + redobuff = old_redobuff; + old_redobuff.bh_first.b_next = NULL; + start_stuff(); + while (read_readbuffers(true) != NUL) {} } /// Save redobuff and old_redobuff to save_redobuff and save_old_redobuff. @@ -476,10 +476,12 @@ void saveRedobuff(save_redo_T *save_redo) // Make a copy, so that ":normal ." in a function works. char *const s = (char *)get_buffcont(&save_redo->sr_redobuff, false); - if (s != NULL) { - add_buff(&redobuff, s, -1L); - xfree(s); + if (s == NULL) { + return; } + + add_buff(&redobuff, s, -1L); + xfree(s); } /// Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff. @@ -527,7 +529,7 @@ void AppendToRedobuffLit(const char *str, int len) s--; } if (s > start) { - add_buff(&redobuff, start, (long)(s - start)); + add_buff(&redobuff, start, s - start); } if (*s == NUL || (len >= 0 && s - str >= len)) { @@ -559,9 +561,7 @@ void AppendCharToRedobuff(int c) } } -/* - * Append a number to the redo buffer. - */ +// Append a number to the redo buffer. void AppendNumberToRedobuff(long n) { if (!block_redo) { @@ -615,9 +615,7 @@ void stuffcharReadbuff(int c) add_char_buff(&readbuf1, c); } -/* - * Append a number to the stuff buffer. - */ +// Append a number to the stuff buffer. void stuffnumReadbuff(long n) { add_num_buff(&readbuf1, n); @@ -783,11 +781,9 @@ 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; @@ -818,21 +814,21 @@ 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) { - typebuf.tb_buf = typebuf_init; - typebuf.tb_noremap = noremapbuf_init; - typebuf.tb_buflen = TYPELEN_INIT; - typebuf.tb_len = 0; - typebuf.tb_off = MAXMAPLEN + 4; - typebuf.tb_change_cnt = 1; + if (typebuf.tb_buf != NULL) { + return; } + + typebuf.tb_buf = typebuf_init; + typebuf.tb_noremap = noremapbuf_init; + typebuf.tb_buflen = TYPELEN_INIT; + typebuf.tb_len = 0; + typebuf.tb_off = MAXMAPLEN + 4; + typebuf.tb_change_cnt = 1; } /// @return true when keys cannot be remapped. @@ -871,7 +867,7 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) typebuf.tb_change_cnt = 1; } - addlen = (int)STRLEN(str); + 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] @@ -939,14 +935,12 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) val = RM_NONE; } - /* - * Adjust typebuf.tb_noremap[] for the new characters: - * If noremap == REMAP_NONE or REMAP_SCRIPT: new characters are - * (sometimes) not remappable - * If noremap == REMAP_YES: all the new characters are mappable - * If noremap > 0: "noremap" characters are not remappable, the rest - * mappable - */ + // Adjust typebuf.tb_noremap[] for the new characters: + // If noremap == REMAP_NONE or REMAP_SCRIPT: new characters are + // (sometimes) not remappable + // If noremap == REMAP_YES: all the new characters are mappable + // If noremap > 0: "noremap" characters are not remappable, the rest + // mappable if (noremap == REMAP_SKIP) { nrm = 1; } else if (noremap < 0) { @@ -1016,18 +1010,14 @@ int typebuf_typed(void) return typebuf.tb_maplen == 0; } -/* - * Return the number of characters that are mapped (or not typed). - */ +// Return 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; @@ -1038,21 +1028,14 @@ void del_typebuf(int len, int offset) typebuf.tb_len -= len; - /* - * Easy case: Just increase typebuf.tb_off. - */ + // Easy case: Just increase typebuf.tb_off. if (offset == 0 && typebuf.tb_buflen - (typebuf.tb_off + len) >= 3 * MAXMAPLEN + 3) { typebuf.tb_off += len; - } - /* - * Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[] - */ - else { + } else { + // Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[] i = typebuf.tb_off + offset; - /* - * Leave some extra room at the end to avoid reallocation. - */ + // Leave some extra room at the end to avoid reallocation. if (typebuf.tb_off > MAXMAPLEN) { memmove(typebuf.tb_buf + MAXMAPLEN, typebuf.tb_buf + typebuf.tb_off, (size_t)offset); @@ -1101,10 +1084,8 @@ void del_typebuf(int len, int offset) } } -/* - * Write typed characters to script file. - * If recording is on put the character in the recordbuffer. - */ +// 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) FUNC_ATTR_NONNULL_ALL { @@ -1155,20 +1136,20 @@ static void gotchars(const char_u *chars, size_t len) /// Only affects recorded characters. void ungetchars(int len) { - if (reg_recording != 0) { - delete_buff_tail(&recordbuff, len); - last_recorded_len -= (size_t)len; + if (reg_recording == 0) { + return; } + + delete_buff_tail(&recordbuff, 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) @@ -1177,9 +1158,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); @@ -1195,9 +1174,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) { @@ -1212,10 +1189,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) @@ -1239,9 +1214,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; @@ -1257,10 +1230,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) { @@ -1304,7 +1275,7 @@ void openscript(char *name, bool directly) // use NameBuff for expanded name expand_env(name, NameBuff, MAXPATHL); int error; - if ((scriptin[curscript] = file_open_new(&error, (char *)NameBuff, + if ((scriptin[curscript] = file_open_new(&error, NameBuff, kFileReadOnly, 0)) == NULL) { semsg(_(e_notopen_2), name, os_strerror(error)); if (curscript) { @@ -1314,12 +1285,10 @@ void openscript(char *name, bool directly) } save_typebuf(); - /* - * Execute the commands from the file right now when using ":source!" - * after ":global" or ":argdo" or in a loop. Also when another command - * follows. This means the display won't be updated. Don't do this - * always, "make test" would fail. - */ + // Execute the commands from the file right now when using ":source!" + // after ":global" or ":argdo" or in a loop. Also when another command + // follows. This means the display won't be updated. Don't do this + // always, "make test" would fail. if (directly) { oparg_T oa; int oldcurscript; @@ -1348,9 +1317,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(); @@ -1452,10 +1419,8 @@ int vgetc(void) garbage_collect(false); } - /* - * If a character was put back with vungetc, it was already processed. - * Return it directly. - */ + // If a character was put back with vungetc, it was already processed. + // Return it directly. if (can_get_old_char()) { c = old_char; old_char = -1; @@ -1628,11 +1593,9 @@ int vgetc(void) last_vgetc_recorded_len = last_recorded_len; } - /* - * In the main loop "may_garbage_collect" can be set to do garbage - * collection in the first next vgetc(). It's disabled after that to - * avoid internally used Lists and Dicts to be freed. - */ + // In the main loop "may_garbage_collect" can be set to do garbage + // collection in the first next vgetc(). It's disabled after that to + // avoid internally used Lists and Dicts to be freed. may_garbage_collect = false; // Execute Lua on_key callbacks. @@ -1641,10 +1604,8 @@ int vgetc(void) 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; @@ -1656,10 +1617,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; @@ -1672,12 +1631,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()) { @@ -1686,11 +1643,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; @@ -1702,10 +1657,8 @@ int vpeekc_any(void) return c; } -/* - * Call vpeekc() without causing anything to be mapped. - * Return true if a character is available, false otherwise. - */ +// Call vpeekc() without causing anything to be mapped. +// Return true if a character is available, false otherwise. int char_avail(void) { int retval; @@ -1726,9 +1679,10 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) no_mapping++; allow_keys++; for (;;) { - // Position the cursor. Needed after a message that ends in a space, - // or if event processing caused a redraw. - ui_cursor_goto(msg_row, msg_col); + if (msg_col > 0) { + // Position the cursor. Needed after a message that ends in a space. + ui_cursor_goto(msg_row, msg_col); + } if (argvars[0].v_type == VAR_UNKNOWN) { // getchar(): blocking wait. @@ -1736,7 +1690,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) if (!char_avail()) { // flush output before waiting ui_flush(); - (void)os_inchar(NULL, 0, -1, 0, main_loop.events); + (void)os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events); if (!multiqueue_empty(main_loop.events)) { state_handle_k_event(); continue; @@ -1766,11 +1720,6 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) no_mapping--; allow_keys--; - if (!ui_has_messages()) { - // redraw the screen after getchar() - update_screen(UPD_NOT_VALID); - } - set_vim_var_nr(VV_MOUSE_WIN, 0); set_vim_var_nr(VV_MOUSE_WINID, 0); set_vim_var_nr(VV_MOUSE_LNUM, 0); @@ -1778,26 +1727,26 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = n; if (n != 0 && (IS_SPECIAL(n) || mod_mask != 0)) { - char_u temp[10]; // modifier: 3, mbyte-char: 6, NUL: 1 + char temp[10]; // modifier: 3, mbyte-char: 6, NUL: 1 int i = 0; // Turn a special key into three bytes, plus modifier. if (mod_mask != 0) { - temp[i++] = K_SPECIAL; - temp[i++] = KS_MODIFIER; - temp[i++] = (char_u)mod_mask; + temp[i++] = (char)K_SPECIAL; + temp[i++] = (char)KS_MODIFIER; + temp[i++] = (char)mod_mask; } if (IS_SPECIAL(n)) { - temp[i++] = K_SPECIAL; - temp[i++] = (char_u)K_SECOND(n); - temp[i++] = K_THIRD(n); + temp[i++] = (char)K_SPECIAL; + temp[i++] = (char)K_SECOND(n); + temp[i++] = (char)K_THIRD(n); } else { - i += utf_char2bytes((int)n, (char *)temp + i); + i += utf_char2bytes((int)n, temp + i); } assert(i < 10); temp[i++] = NUL; rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char *)vim_strsave(temp); + rettv->vval.v_string = xstrdup(temp); if (is_mouse_key((int)n)) { int row = mouse_row; @@ -1838,19 +1787,21 @@ void f_getcharstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getchar_common(argvars, rettv); - if (rettv->v_type == VAR_NUMBER) { - char temp[7]; // mbyte-char: 6, NUL: 1 - const varnumber_T n = rettv->vval.v_number; - int i = 0; + if (rettv->v_type != VAR_NUMBER) { + return; + } - if (n != 0) { - i += utf_char2bytes((int)n, (char *)temp); - } - assert(i < 7); - temp[i++] = NUL; - rettv->v_type = VAR_STRING; - rettv->vval.v_string = xstrdup(temp); + char temp[7]; // mbyte-char: 6, NUL: 1 + const varnumber_T n = rettv->vval.v_number; + int i = 0; + + if (n != 0) { + i += utf_char2bytes((int)n, (char *)temp); } + assert(i < 7); + temp[i++] = NUL; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = xstrdup(temp); } /// "getcharmod()" function @@ -1961,7 +1912,7 @@ static int check_simplify_modifier(int max_offset) /// - When there is no match yet, return map_result_nomatch, need to get more /// typeahead. /// - On failure (out of memory) return map_result_fail. -static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) +static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) { mapblock_T *mp = NULL; mapblock_T *mp2; @@ -2031,21 +1982,33 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // Only consider an entry if the first character matches and it is // for the current state. // Skip ":lmap" mappings if keys were mapped. - if (mp->m_keys[0] == tb_c1 && (mp->m_mode & local_State) + if ((uint8_t)mp->m_keys[0] == tb_c1 && (mp->m_mode & local_State) && ((mp->m_mode & MODE_LANGMAP) == 0 || typebuf.tb_maplen == 0)) { int nomap = nolmaplen; - int c2; + int modifiers = 0; // find the match length of this mapping for (mlen = 1; mlen < typebuf.tb_len; mlen++) { - c2 = typebuf.tb_buf[typebuf.tb_off + mlen]; + int c2 = typebuf.tb_buf[typebuf.tb_off + mlen]; if (nomap > 0) { + if (nomap == 2 && c2 == KS_MODIFIER) { + modifiers = 1; + } else if (nomap == 1 && modifiers == 1) { + modifiers = c2; + } nomap--; - } else if (c2 == K_SPECIAL) { - nomap = 2; } else { - LANGMAP_ADJUST(c2, true); + if (c2 == K_SPECIAL) { + nomap = 2; + } else if (merge_modifiers(c2, &modifiers) == c2) { + // Only apply 'langmap' if merging modifiers into + // the key will not result in another character, + // so that 'langmap' behaves consistently in + // different terminals and GUIs. + LANGMAP_ADJUST(c2, true); + } + modifiers = 0; } - if (mp->m_keys[mlen] != c2) { + if ((uint8_t)mp->m_keys[mlen] != c2) { break; } } @@ -2053,7 +2016,7 @@ static int handle_mapping(int *keylenp, 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 = mp->m_keys; + char_u *p1 = (char_u *)mp->m_keys; char_u *p2 = (char_u *)mb_unescape((const char **)&p1); if (p2 != NULL && MB_BYTE2LEN(tb_c1) > utfc_ptr2len((char *)p2)) { @@ -2071,8 +2034,8 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // mapping starts with K_SNR. uint8_t *s = typebuf.tb_noremap + typebuf.tb_off; if (*s == RM_SCRIPT - && (mp->m_keys[0] != K_SPECIAL - || mp->m_keys[1] != KS_EXTRA + && ((uint8_t)mp->m_keys[0] != K_SPECIAL + || (uint8_t)mp->m_keys[1] != KS_EXTRA || mp->m_keys[2] != KE_SNR)) { continue; } @@ -2179,7 +2142,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) } else { keylen = 0; } - if (keylen == 0) { // no simplication has been done + if (keylen == 0) { // no simplification has been done // If there was no mapping at all use the character from the // typeahead buffer right here. if (mp == NULL) { @@ -2205,7 +2168,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // complete match if (keylen >= 0 && keylen <= typebuf.tb_len) { - char_u *map_str = NULL; + char *map_str = NULL; // Write chars to script file(s). // Note: :lmap mappings are written *after* being applied. #5658 @@ -2242,12 +2205,12 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // Copy the values from *mp that are used, because evaluating the // expression may invoke a function that redefines the mapping, thereby // making *mp invalid. - char save_m_expr = mp->m_expr; - int save_m_noremap = mp->m_noremap; - char save_m_silent = mp->m_silent; - char_u *save_m_keys = NULL; // only saved when needed - char_u *save_m_str = NULL; // only saved when needed - LuaRef save_m_luaref = mp->m_luaref; + const bool save_m_expr = mp->m_expr; + const int save_m_noremap = mp->m_noremap; + const bool save_m_silent = mp->m_silent; + char *save_m_keys = NULL; // only saved when needed + char *save_m_str = NULL; // only saved when needed + const LuaRef save_m_luaref = mp->m_luaref; // Handle ":map <expr>": evaluate the {rhs} as an // expression. Also save and restore the command line @@ -2263,9 +2226,9 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) vgetc_busy = 0; may_garbage_collect = false; - save_m_keys = vim_strsave(mp->m_keys); + save_m_keys = xstrdup(mp->m_keys); if (save_m_luaref == LUA_NOREF) { - save_m_str = vim_strsave((char_u *)mp->m_str); + save_m_str = xstrdup(mp->m_str); } map_str = eval_map_expr(mp, NUL); @@ -2277,13 +2240,13 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // 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_u buf[4]; + char buf[4]; xfree(map_str); - buf[0] = K_SPECIAL; - buf[1] = KS_EXTRA; + buf[0] = (char)K_SPECIAL; + buf[1] = (char)KS_EXTRA; buf[2] = KE_IGNORE; buf[3] = NUL; - map_str = vim_strsave(buf); + map_str = xstrdup(buf); if (State & MODE_CMDLINE) { // redraw the command below the error msg_didout = true; @@ -2297,7 +2260,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) vgetc_busy = save_vgetc_busy; may_garbage_collect = save_may_garbage_collect; } else { - map_str = (char_u *)mp->m_str; + map_str = mp->m_str; } // Insert the 'to' part in the typebuf.tb_buf. @@ -2312,18 +2275,18 @@ static int handle_mapping(int *keylenp, 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(map_str, STRLEN(map_str)); + gotchars((char_u *)map_str, strlen(map_str)); } if (save_m_noremap != REMAP_YES) { noremap = save_m_noremap; - } else if (STRNCMP(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys, + } else if (strncmp(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys, (size_t)keylen) != 0) { noremap = REMAP_YES; } else { noremap = REMAP_SKIP; } - i = ins_typebuf((char *)map_str, noremap, 0, true, cmd_silent || save_m_silent); + i = ins_typebuf(map_str, noremap, 0, true, cmd_silent || save_m_silent); if (save_m_expr) { xfree(map_str); } @@ -2393,7 +2356,9 @@ void check_end_reg_executing(bool advance) static int vgetorpeek(bool advance) { int c, c1; - bool timedout = false; // waited for more than 1 second for mapping to complete + 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; @@ -2566,10 +2531,10 @@ static int vgetorpeek(bool advance) // white-space, so find the last non-white // character -- webb curwin->w_wcol = 0; - ptr = get_cursor_line_ptr(); + ptr = (char_u *)get_cursor_line_ptr(); chartabsize_T cts; init_chartabsize_arg(&cts, curwin, - curwin->w_cursor.lnum, 0, ptr, ptr); + curwin->w_cursor.lnum, 0, (char *)ptr, (char *)ptr); while ((char_u *)cts.cts_ptr < ptr + curwin->w_cursor.col) { if (!ascii_iswhite(*cts.cts_ptr)) { curwin->w_wcol = cts.cts_vcol; @@ -2596,8 +2561,8 @@ 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 = get_cursor_line_ptr(); - col -= utf_head_off(ptr, ptr + col); + ptr = (char_u *)get_cursor_line_ptr(); + col -= utf_head_off((char *)ptr, (char *)ptr + col); if (utf_ptr2cells((char *)ptr + col) > 1) { curwin->w_wcol--; } @@ -2676,7 +2641,7 @@ static int vgetorpeek(bool advance) // input buffer (e.g., termresponse). if (((State & MODE_INSERT) != 0 || p_lz) && (State & MODE_CMDLINE) == 0 && advance && must_redraw != 0 && !need_wait_return) { - update_screen(0); + update_screen(); setcursor(); // put cursor back where it belongs } @@ -2851,11 +2816,9 @@ int inchar(char_u *buf, int maxlen, long wait_time) ui_flush(); } - /* - * Don't reset these when at the hit-return prompt, otherwise an endless - * recursive loop may result (write error in swapfile, hit-return, timeout - * on char wait, flush swapfile, write error....). - */ + // Don't reset these when at the hit-return prompt, otherwise an endless + // recursive loop may result (write error in swapfile, hit-return, timeout + // on char wait, flush swapfile, write error....). if (State != MODE_HITRETURN) { did_outofmem_msg = false; // display out of memory message (again) did_swapwrite_msg = false; // display swap file write error again |