aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/getchar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/getchar.c')
-rw-r--r--src/nvim/getchar.c204
1 files changed, 122 insertions, 82 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 4135065787..9c5364e1b1 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"
@@ -139,11 +151,11 @@ void free_buff(buffheader_T *buf)
/// K_SPECIAL in the returned string is escaped.
///
/// @param dozero count == zero is not an error
-static char_u *get_buffcont(buffheader_T *buffer, int dozero)
+static char *get_buffcont(buffheader_T *buffer, int dozero)
{
size_t count = 0;
- char_u *p = NULL;
- char_u *p2;
+ char *p = NULL;
+ char *p2;
// compute the total length of the string
for (const buffblock_T *bp = buffer->bh_first.b_next;
@@ -156,7 +168,7 @@ static char_u *get_buffcont(buffheader_T *buffer, int dozero)
p2 = p;
for (const buffblock_T *bp = buffer->bh_first.b_next;
bp != NULL; bp = bp->b_next) {
- for (const char_u *str = (char_u *)bp->b_str; *str;) {
+ for (const char *str = bp->b_str; *str;) {
*p2++ = *str++;
}
}
@@ -170,7 +182,7 @@ 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);
@@ -178,7 +190,7 @@ char_u *get_recorded(void)
// Remove the characters that were added the last time, these must be the
// (possibly mapped) characters that stopped the recording.
- len = STRLEN(p);
+ len = strlen(p);
if (len >= last_recorded_len) {
len -= last_recorded_len;
p[len] = NUL;
@@ -190,12 +202,12 @@ char_u *get_recorded(void)
p[len - 1] = NUL;
}
- return p;
+ return (char_u *)p;
}
/// Return the contents of the redo buffer as a single string.
/// K_SPECIAL in the returned string is escaped.
-char_u *get_inserted(void)
+char *get_inserted(void)
{
return get_buffcont(&redobuff, false);
}
@@ -232,7 +244,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle
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);
+ xstrlcpy(buf->bh_curr->b_str + len, s, (size_t)slen + 1);
buf->bh_space -= (size_t)slen;
} else {
if (slen < MINIMAL_SIZE) {
@@ -242,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;
@@ -260,10 +272,12 @@ static void delete_buff_tail(buffheader_T *buf, int slen)
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;
+ if (len < slen) {
+ return;
}
+
+ buf->bh_curr->b_str[len - slen] = NUL;
+ buf->bh_space += (size_t)slen;
}
/// Add number "n" to buffer "buf".
@@ -427,24 +441,28 @@ void beep_flush(void)
// 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.
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.
@@ -457,11 +475,13 @@ void saveRedobuff(save_redo_T *save_redo)
old_redobuff.bh_first.b_next = NULL;
// 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);
+ char *const s = get_buffcont(&save_redo->sr_redobuff, false);
+ if (s == NULL) {
+ return;
}
+
+ add_buff(&redobuff, s, -1L);
+ xfree(s);
}
/// Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff.
@@ -509,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)) {
@@ -518,7 +538,7 @@ void AppendToRedobuffLit(const char *str, int len)
// Handle a special or multibyte character.
// Composing chars separately are handled separately.
- const int c = mb_cptr2char_adv((const char_u **)&s);
+ const int c = mb_cptr2char_adv(&s);
if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^'))) {
add_char_buff(&redobuff, Ctrl_V);
}
@@ -579,7 +599,7 @@ void stuffReadbuffSpec(const char *s)
stuffReadbuffLen(s, 3);
s += 3;
} else {
- int c = mb_cptr2char_adv((const char_u **)&s);
+ int c = mb_cptr2char_adv(&s);
if (c == CAR || c == NL || c == ESC) {
c = ' ';
}
@@ -620,7 +640,7 @@ void stuffescaped(const char *arg, bool literally)
// stuff a single special character
if (*arg != NUL) {
- const int c = mb_cptr2char_adv((const char_u **)&arg);
+ const int c = mb_cptr2char_adv(&arg);
if (literally && ((c < ' ' && c != TAB) || c == DEL)) {
stuffcharReadbuff(Ctrl_V);
}
@@ -799,14 +819,16 @@ void stop_redo_ins(void)
// 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.
@@ -864,7 +886,7 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent)
// often.
int newoff = MAXMAPLEN + 4;
int extra = addlen + newoff + 4 * (MAXMAPLEN + 4);
- if (typebuf.tb_len > 2147483674 - extra) {
+ if (typebuf.tb_len > INT_MAX - extra) {
// string is getting too long for 32 bit int
emsg(_(e_toocompl)); // also calls flush_buffers
setcursor();
@@ -1114,10 +1136,12 @@ 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
@@ -1251,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) {
@@ -1763,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
@@ -1886,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;
@@ -1956,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;
}
}
@@ -1978,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)) {
@@ -1996,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;
}
@@ -2167,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;
+ 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
- LuaRef save_m_luaref = mp->m_luaref;
+ const LuaRef save_m_luaref = mp->m_luaref;
// Handle ":map <expr>": evaluate the {rhs} as an
// expression. Also save and restore the command line
@@ -2188,7 +2226,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
vgetc_busy = 0;
may_garbage_collect = false;
- save_m_keys = xstrdup((char *)mp->m_keys);
+ save_m_keys = xstrdup(mp->m_keys);
if (save_m_luaref == LUA_NOREF) {
save_m_str = xstrdup(mp->m_str);
}
@@ -2237,12 +2275,12 @@ 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((char_u *)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 : (char *)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 {
@@ -2318,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;
@@ -2953,16 +2993,16 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
ga_concat(&line_ga, "<SNR>");
} else {
if (cmod != 0) {
- ga_append(&line_ga, (char)K_SPECIAL);
- ga_append(&line_ga, (char)KS_MODIFIER);
- ga_append(&line_ga, (char)cmod);
+ ga_append(&line_ga, K_SPECIAL);
+ ga_append(&line_ga, KS_MODIFIER);
+ ga_append(&line_ga, (uint8_t)cmod);
}
if (IS_SPECIAL(c1)) {
- ga_append(&line_ga, (char)K_SPECIAL);
- ga_append(&line_ga, (char)K_SECOND(c1));
- ga_append(&line_ga, (char)K_THIRD(c1));
+ ga_append(&line_ga, K_SPECIAL);
+ ga_append(&line_ga, (uint8_t)K_SECOND(c1));
+ ga_append(&line_ga, (uint8_t)K_THIRD(c1));
} else {
- ga_append(&line_ga, (char)c1);
+ ga_append(&line_ga, (uint8_t)c1);
}
}
@@ -2998,7 +3038,7 @@ bool map_execute_lua(void)
} else if (c1 == '\r' || c1 == '\n') {
c1 = NUL; // end the line
} else {
- ga_append(&line_ga, (char)c1);
+ ga_append(&line_ga, (uint8_t)c1);
}
}