diff options
Diffstat (limited to 'src/nvim/edit.c')
| -rw-r--r-- | src/nvim/edit.c | 192 | 
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) | 
