aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/edit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/edit.c')
-rw-r--r--src/nvim/edit.c192
1 files changed, 106 insertions, 86 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index b35504908e..a1987cf2d5 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1,3 +1,6 @@
+// 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
+
/*
* edit.c: functions for Insert mode
*/
@@ -459,7 +462,7 @@ static void insert_enter(InsertState *s)
// Always update o_lnum, so that a "CTRL-O ." that adds a line
// still puts the cursor back after the inserted text.
- if (ins_at_eol && gchar_cursor() == NUL) {
+ if (ins_at_eol) {
o_lnum = curwin->w_cursor.lnum;
}
@@ -844,7 +847,7 @@ static int insert_handle_key(InsertState *s)
case ' ':
- if (mod_mask != 4) {
+ if (mod_mask != MOD_MASK_CTRL) {
goto normalchar;
}
// FALLTHROUGH
@@ -971,12 +974,8 @@ static int insert_handle_key(InsertState *s)
multiqueue_process_events(main_loop.events);
break;
- case K_FOCUSGAINED: // Neovim has been given focus
- apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
- break;
-
- case K_FOCUSLOST: // Neovim has lost focus
- apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
+ case K_COMMAND: // some command
+ do_cmdline(NULL, getcmdkeycmd, NULL, 0);
break;
case K_HOME: // <Home>
@@ -1181,6 +1180,14 @@ static int insert_handle_key(InsertState *s)
normalchar:
// Insert a normal character.
+
+ if (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META) {
+ // Unmapped ALT/META chord behaves like ESC+c. #8213
+ stuffcharReadbuff(ESC);
+ stuffcharReadbuff(s->c);
+ break;
+ }
+
if (!p_paste) {
// Trigger InsertCharPre.
char_u *str = do_insert_char_pre(s->c);
@@ -1433,7 +1440,7 @@ static void ins_ctrl_v(void)
* line and will not removed by the redraw */
edit_unputchar();
clear_showcmd();
- insert_special(c, FALSE, TRUE);
+ insert_special(c, true, true);
revins_chars++;
revins_legal++;
}
@@ -1932,7 +1939,7 @@ bool vim_is_ctrl_x_key(int c)
case CTRL_X_EVAL:
return (c == Ctrl_P || c == Ctrl_N);
}
- EMSG(_(e_internal));
+ internal_error("vim_is_ctrl_x_key()");
return false;
}
@@ -2037,12 +2044,12 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
} else {
c = *(p++);
}
- if (vim_islower(c)) {
+ if (mb_islower(c)) {
has_lower = true;
- if (vim_isupper(wca[i])) {
+ if (mb_isupper(wca[i])) {
// Rule 1 is satisfied.
for (i = actual_compl_length; i < actual_len; i++) {
- wca[i] = vim_tolower(wca[i]);
+ wca[i] = mb_tolower(wca[i]);
}
break;
}
@@ -2062,14 +2069,14 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
} else {
c = *(p++);
}
- if (was_letter && vim_isupper(c) && vim_islower(wca[i])) {
+ if (was_letter && mb_isupper(c) && mb_islower(wca[i])) {
// Rule 2 is satisfied.
for (i = actual_compl_length; i < actual_len; i++) {
- wca[i] = vim_toupper(wca[i]);
+ wca[i] = mb_toupper(wca[i]);
}
break;
}
- was_letter = vim_islower(c) || vim_isupper(c);
+ was_letter = mb_islower(c) || mb_isupper(c);
}
}
@@ -2082,10 +2089,10 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
} else {
c = *(p++);
}
- if (vim_islower(c)) {
- wca[i] = vim_tolower(wca[i]);
- } else if (vim_isupper(c)) {
- wca[i] = vim_toupper(wca[i]);
+ if (mb_islower(c)) {
+ wca[i] = mb_tolower(wca[i]);
+ } else if (mb_isupper(c)) {
+ wca[i] = mb_toupper(wca[i]);
}
}
}
@@ -2302,9 +2309,10 @@ static void ins_compl_longest_match(compl_T *match)
c1 = *p;
c2 = *s;
}
- if (match->cp_icase ? (vim_tolower(c1) != vim_tolower(c2))
- : (c1 != c2))
+ if (match->cp_icase ? (mb_tolower(c1) != mb_tolower(c2))
+ : (c1 != c2)) {
break;
+ }
if (has_mbyte) {
mb_ptr_adv(p);
mb_ptr_adv(s);
@@ -2402,6 +2410,7 @@ void set_completion(colnr_T startcol, list_T *list)
ins_compl_prep(' ');
}
ins_compl_clear();
+ ins_compl_free();
compl_direction = FORWARD;
if (startcol > curwin->w_cursor.col)
@@ -3162,8 +3171,7 @@ static bool ins_compl_prep(int c)
/* Ignore end of Select mode mapping and mouse scroll buttons. */
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
- || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
- || c == K_FOCUSGAINED || c == K_FOCUSLOST) {
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT) {
return retval;
}
@@ -3426,10 +3434,10 @@ static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
len -= (*mb_head_off)(p, p + len);
for (p += len; *p != NUL; mb_ptr_adv(p))
AppendCharToRedobuff(K_BS);
- } else
+ } else {
len = 0;
- if (ptr != NULL)
- AppendToRedobuffLit(ptr + len, -1);
+ }
+ AppendToRedobuffLit(ptr + len, -1);
}
/*
@@ -3540,19 +3548,19 @@ theend:
/*
* Add completions from a list.
*/
-static void ins_compl_add_list(list_T *list)
+static void ins_compl_add_list(list_T *const list)
{
- listitem_T *li;
int dir = compl_direction;
- /* Go through the List with matches and add each of them. */
- for (li = list->lv_first; li != NULL; li = li->li_next) {
- if (ins_compl_add_tv(&li->li_tv, dir) == OK)
- /* if dir was BACKWARD then honor it just once */
+ // Go through the List with matches and add each of them.
+ TV_LIST_ITER(list, li, {
+ if (ins_compl_add_tv(TV_LIST_ITEM_TV(li), dir) == OK) {
+ // If dir was BACKWARD then honor it just once.
dir = FORWARD;
- else if (did_emsg)
+ } else if (did_emsg) {
break;
- }
+ }
+ });
}
/*
@@ -3604,6 +3612,8 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
+ cptext[CPT_USER_DATA] = tv_dict_get_string(tv->vval.v_dict,
+ "user_data", true);
icase = (bool)tv_dict_get_number(tv->vval.v_dict, "icase");
adup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
@@ -3613,6 +3623,9 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
memset(cptext, 0, sizeof(cptext));
}
if (word == NULL || (!aempty && *word == NUL)) {
+ for (size_t i = 0; i < CPT_COUNT; i++) {
+ xfree(cptext[i]);
+ }
return FAIL;
}
return ins_compl_add((char_u *)word, -1, icase, NULL,
@@ -4047,8 +4060,9 @@ static void ins_compl_insert(int in_compl_func)
// Set completed item.
// { word, abbr, menu, kind, info }
dict_T *dict = tv_dict_alloc();
- tv_dict_add_str(dict, S_LEN("word"),
- (const char *)EMPTY_IF_NULL(compl_shown_match->cp_str));
+ tv_dict_add_str(
+ dict, S_LEN("word"),
+ (const char *)EMPTY_IF_NULL(compl_shown_match->cp_str));
tv_dict_add_str(
dict, S_LEN("abbr"),
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR]));
@@ -4061,6 +4075,9 @@ static void ins_compl_insert(int in_compl_func)
tv_dict_add_str(
dict, S_LEN("info"),
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO]));
+ tv_dict_add_str(
+ dict, S_LEN("user_data"),
+ (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_USER_DATA]));
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
if (!in_compl_func) {
compl_curr_match = compl_shown_match;
@@ -4685,7 +4702,7 @@ static int ins_complete(int c, bool enable_pum)
line = ml_get(curwin->w_cursor.lnum);
compl_pattern = vim_strnsave(line + compl_col, compl_length);
} else {
- EMSG2(_(e_intern2), "ins_complete()");
+ internal_error("ins_complete()");
return FAIL;
}
@@ -4910,14 +4927,17 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len)
if (ctrl_x_mode == CTRL_X_DICTIONARY
|| ctrl_x_mode == CTRL_X_THESAURUS)
break;
+ // fallthrough
case '~':
if (!p_magic) /* quote these only if magic is set */
break;
+ // fallthrough
case '\\':
if (ctrl_x_mode == CTRL_X_DICTIONARY
|| ctrl_x_mode == CTRL_X_THESAURUS)
break;
- case '^': /* currently it's not needed. */
+ // fallthrough
+ case '^': // currently it's not needed.
case '$':
m++;
if (dest != NULL)
@@ -5045,13 +5065,11 @@ static void insert_special(int c, int allow_modmask, int ctrlv)
char_u *p;
int len;
- /*
- * Special function key, translate into "<Key>". Up to the last '>' is
- * inserted with ins_str(), so as not to replace characters in replace
- * mode.
- * Only use mod_mask for special keys, to avoid things like <S-Space>,
- * unless 'allow_modmask' is TRUE.
- */
+ // Special function key, translate into "<Key>". Up to the last '>' is
+ // inserted with ins_str(), so as not to replace characters in replace
+ // mode.
+ // Only use mod_mask for special keys, to avoid things like <S-Space>,
+ // unless 'allow_modmask' is TRUE.
if (mod_mask & MOD_MASK_CMD) { // Command-key never produces a normal key.
allow_modmask = true;
}
@@ -5236,28 +5254,27 @@ insertchar (
buf[0] = c;
i = 1;
- if (textwidth > 0)
+ if (textwidth > 0) {
virtcol = get_nolist_virtcol();
- /*
- * Stop the string when:
- * - no more chars available
- * - finding a special character (command key)
- * - buffer is full
- * - running into the 'textwidth' boundary
- * - need to check for abbreviation: A non-word char after a word-char
- */
- while ( (c = vpeekc()) != NUL
- && !ISSPECIAL(c)
- && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
- && i < INPUT_BUFLEN
- && (textwidth == 0
- || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
- && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1]))) {
+ }
+ // Stop the string when:
+ // - no more chars available
+ // - finding a special character (command key)
+ // - buffer is full
+ // - running into the 'textwidth' boundary
+ // - need to check for abbreviation: A non-word char after a word-char
+ while ((c = vpeekc()) != NUL
+ && !ISSPECIAL(c)
+ && MB_BYTE2LEN(c) == 1
+ && i < INPUT_BUFLEN
+ && !(p_fkmap && KeyTyped) // Farsi mode mapping moves cursor
+ && (textwidth == 0
+ || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
+ && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1]))) {
c = vgetc();
- if (p_hkmap && KeyTyped)
- c = hkmap(c); /* Hebrew mode mapping */
- if (p_fkmap && KeyTyped)
- c = fkmap(c); /* Farsi mode mapping */
+ if (p_hkmap && KeyTyped) {
+ c = hkmap(c); // Hebrew mode mapping
+ }
buf[i++] = c;
}
@@ -6067,27 +6084,30 @@ void free_last_insert(void)
#endif
-/*
- * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL
- * and CSI. Handle multi-byte characters.
- * Returns a pointer to after the added bytes.
- */
+/// Add character "c" to buffer "s"
+///
+/// Escapes the special meaning of K_SPECIAL and CSI, handles multi-byte
+/// characters.
+///
+/// @param[in] c Character to add.
+/// @param[out] s Buffer to add to. Must have at least MB_MAXBYTES + 1 bytes.
+///
+/// @return Pointer to after the added bytes.
char_u *add_char2buf(int c, char_u *s)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
char_u temp[MB_MAXBYTES + 1];
- int i;
- int len;
-
- len = (*mb_char2bytes)(c, temp);
- for (i = 0; i < len; ++i) {
+ const int len = utf_char2bytes(c, temp);
+ for (int i = 0; i < len; i++) {
c = temp[i];
- /* Need to escape K_SPECIAL and CSI like in the typeahead buffer. */
+ // Need to escape K_SPECIAL and CSI like in the typeahead buffer.
if (c == K_SPECIAL) {
*s++ = K_SPECIAL;
*s++ = KS_SPECIAL;
*s++ = KE_FILLER;
- } else
+ } else {
*s++ = c;
+ }
}
return s;
}
@@ -6905,7 +6925,9 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
if (try_match && *look == keytyped) {
return true;
}
- look++;
+ if (*look != NUL) {
+ look++;
+ }
}
/*
@@ -7471,13 +7493,11 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
int oldState;
int cpc[MAX_MCO]; /* composing characters */
- /*
- * can't delete anything in an empty file
- * can't backup past first character in buffer
- * can't backup past starting point unless 'backspace' > 1
- * can backup to a previous line if 'backspace' == 0
- */
- if (bufempty()
+ // can't delete anything in an empty file
+ // can't backup past first character in buffer
+ // can't backup past starting point unless 'backspace' > 1
+ // can backup to a previous line if 'backspace' == 0
+ if (BUFEMPTY()
|| (!revins_on
&& ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
|| (!can_bs(BS_START)