diff options
Diffstat (limited to 'src/nvim/normal.c')
| -rw-r--r-- | src/nvim/normal.c | 276 | 
1 files changed, 170 insertions, 106 deletions
| diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 388ddfc8bb..e4310de5d8 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.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 +  /*   * normal.c:	Contains the main routine for processing characters in command   *		mode.  Communicates closely with the code in ops.c to handle @@ -10,6 +13,7 @@  #include <stdbool.h>  #include <stdlib.h> +#include "nvim/log.h"  #include "nvim/vim.h"  #include "nvim/ascii.h"  #include "nvim/normal.h" @@ -341,8 +345,7 @@ static const struct nv_cmd {    { K_F8,      farsi_f8,       0,                      0 },    { K_F9,      farsi_f9,       0,                      0 },    { K_EVENT,   nv_event,       NV_KEEPREG,             0 }, -  { K_FOCUSGAINED, nv_focusgained, NV_KEEPREG,         0 }, -  { K_FOCUSLOST,   nv_focuslost,   NV_KEEPREG,         0 }, +  { K_COMMAND, nv_colon,       0,                      0 },  };  /* Number of commands in nv_cmds[]. */ @@ -538,7 +541,7 @@ static bool normal_handle_special_visual_command(NormalState *s)    return false;  } -static bool normal_need_aditional_char(NormalState *s) +static bool normal_need_additional_char(NormalState *s)  {    int flags = nv_cmds[s->idx].cmd_flags;    bool pending_op = s->oa.op_type != OP_NOP; @@ -694,7 +697,6 @@ static void normal_get_additional_char(NormalState *s)      if (langmap_active) {        // Undo the decrement done above        no_mapping++; -      State = NORMAL_BUSY;      }      State = NORMAL_BUSY;      s->need_flushbuf |= add_to_showcmd(*cp); @@ -1081,7 +1083,7 @@ static int normal_execute(VimState *state, int key)    }    // Get an additional character if we need one. -  if (normal_need_aditional_char(s)) { +  if (normal_need_additional_char(s)) {      normal_get_additional_char(s);    } @@ -1449,9 +1451,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)      /* Never redo "zf" (define fold). */      if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)          && ((!VIsual_active || oap->motion_force) -            /* Also redo Operator-pending Visual mode mappings */ -            || (VIsual_active && cap->cmdchar == ':' -                && oap->op_type != OP_COLON)) +            // Also redo Operator-pending Visual mode mappings. +            || (cap->cmdchar == ':' && oap->op_type != OP_COLON))          && cap->cmdchar != 'D'          && oap->op_type != OP_FOLD          && oap->op_type != OP_FOLDOPEN @@ -1473,13 +1474,13 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)            AppendToRedobuffLit(cap->searchbuf, -1);          }          AppendToRedobuff(NL_STR); -      } else if (cap->cmdchar == ':') { -        /* do_cmdline() has stored the first typed line in -         * "repeat_cmdline".  When several lines are typed repeating -         * won't be possible. */ -        if (repeat_cmdline == NULL) +      } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) { +        // do_cmdline() has stored the first typed line in +        // "repeat_cmdline".  When several lines are typed repeating +        // won't be possible. +        if (repeat_cmdline == NULL) {            ResetRedobuff(); -        else { +        } else {            AppendToRedobuffLit(repeat_cmdline, -1);            AppendToRedobuff(NL_STR);            xfree(repeat_cmdline); @@ -1548,8 +1549,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)        }        oap->start = VIsual; -      if (VIsual_mode == 'V') +      if (VIsual_mode == 'V') {          oap->start.col = 0; +        oap->start.coladd = 0; +      }      }      /* @@ -1635,16 +1638,22 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)          /* Prepare for redoing.  Only use the nchar field for "r",           * otherwise it might be the second char of the operator. */          if (cap->cmdchar == 'g' && (cap->nchar == 'n' -                                    || cap->nchar == 'N')) +                                    || cap->nchar == 'N')) {            prep_redo(oap->regname, cap->count0, -              get_op_char(oap->op_type), get_extra_op_char(oap->op_type), -              oap->motion_force, cap->cmdchar, cap->nchar); -        else if (cap->cmdchar != ':') -          prep_redo(oap->regname, 0L, NUL, 'v', -              get_op_char(oap->op_type), -              get_extra_op_char(oap->op_type), -              oap->op_type == OP_REPLACE -              ? cap->nchar : NUL); +                    get_op_char(oap->op_type), get_extra_op_char(oap->op_type), +                    oap->motion_force, cap->cmdchar, cap->nchar); +        } else if (cap->cmdchar != ':') { +          int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL; + +          // reverse what nv_replace() did +          if (nchar == REPLACE_CR_NCHAR) { +            nchar = CAR; +          } else if (nchar == REPLACE_NL_NCHAR) { +            nchar = NL; +          } +          prep_redo(oap->regname, 0L, NUL, 'v', get_op_char(oap->op_type), +                    get_extra_op_char(oap->op_type), nchar); +        }          if (!redo_VIsual_busy) {            redo_VIsual_mode = resel_VIsual_mode;            redo_VIsual_vcol = resel_VIsual_vcol; @@ -1859,6 +1868,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)        } else {          bangredo = true;  // do_bang() will put cmd in redo buffer.        } +      // fallthrough      case OP_INDENT:      case OP_COLON: @@ -1941,8 +1951,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)           * the lines. */          auto_format(false, true); -        if (restart_edit == 0) +        if (restart_edit == 0) {            restart_edit = restart_edit_save; +        } else { +          cap->retval |= CA_COMMAND_BUSY; +        }        }        break; @@ -2334,10 +2347,11 @@ do_mouse (          if (regname == 0 && eval_has_provider("clipboard")) {            regname = '*';          } -        if ((State & REPLACE_FLAG) && !yank_register_mline(regname)) +        if ((State & REPLACE_FLAG) && !yank_register_mline(regname)) {            insert_reg(regname, true); -        else { -          do_put(regname, NULL, BACKWARD, 1L, fixindent | PUT_CURSEND); +        } else { +          do_put(regname, NULL, BACKWARD, 1L, +                 (fixindent ? PUT_FIXINDENT : 0) | PUT_CURSEND);            /* Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r */            AppendCharToRedobuff(Ctrl_R); @@ -2689,7 +2703,8 @@ do_mouse (       */      if (restart_edit != 0)        where_paste_started = curwin->w_cursor; -    do_put(regname, NULL, dir, count, fixindent | PUT_CURSEND); +    do_put(regname, NULL, dir, count, +           (fixindent ? PUT_FIXINDENT : 0)| PUT_CURSEND);    }    /*     * Ctrl-Mouse click or double click in a quickfix window jumps to the @@ -3653,6 +3668,39 @@ nv_gd (    }  } +// Return true if line[offset] is not inside a C-style comment or string, false +// otherwise. +static bool is_ident(char_u *line, int offset) +{ +  bool incomment = false; +  int instring = 0; +  int prev = 0; + +  for (int i = 0; i < offset && line[i] != NUL; i++) { +    if (instring != 0) { +      if (prev != '\\' && line[i] == instring) { +        instring = 0; +      } +    } else if ((line[i] == '"' || line[i] == '\'') && !incomment) { +      instring = line[i]; +    } else { +      if (incomment) { +        if (prev == '*' && line[i] == '/') { +          incomment = false; +        } +      } else if (prev == '/' && line[i] == '*') { +        incomment = true; +      } else if (prev == '/' && line[i] == '/') { +        return false; +      } +    } + +    prev = line[i]; +  } + +  return incomment == false && instring == 0; +} +  /*   * Search for variable declaration of "ptr[len]".   * When "locally" is true in the current function ("gd"), otherwise in the @@ -3679,6 +3727,7 @@ find_decl (    bool retval = true;    bool incll;    int searchflags = flags_arg; +  bool valid;    pat = xmalloc(len + 7); @@ -3713,6 +3762,7 @@ find_decl (    /* Search forward for the identifier, ignore comment lines. */    clearpos(&found_pos);    for (;; ) { +    valid = false;      t = searchit(curwin, curbuf, &curwin->w_cursor, FORWARD,          pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL);      if (curwin->w_cursor.lnum >= old_pos.lnum) @@ -3743,20 +3793,35 @@ find_decl (        curwin->w_cursor.col = 0;        continue;      } -    if (!locally)       /* global search: use first match found */ +    valid = is_ident(get_cursor_line_ptr(), curwin->w_cursor.col); + +    // If the current position is not a valid identifier and a previous match is +    // present, favor that one instead. +    if (!valid && found_pos.lnum != 0) { +      curwin->w_cursor = found_pos;        break; -    if (curwin->w_cursor.lnum >= par_pos.lnum) { -      /* If we previously found a valid position, use it. */ -      if (found_pos.lnum != 0) +    } +    // global search: use first match found +    if (valid && !locally) { +      break; +    } +    if (valid && curwin->w_cursor.lnum >= par_pos.lnum) { +      // If we previously found a valid position, use it. +      if (found_pos.lnum != 0) {          curwin->w_cursor = found_pos; +      }        break;      } -    // For finding a local variable and the match is before the "{" search -    // to find a later match.  For K&R style function declarations this -    // skips the function header without types.  Remove SEARCH_START from -    // flags to avoid getting stuck at one position. -    found_pos = curwin->w_cursor; +    // For finding a local variable and the match is before the "{" or +    // inside a comment, continue searching.  For K&R style function +    // declarations this skips the function header without types. +    if (!valid) { +      clearpos(&found_pos); +    } else { +      found_pos = curwin->w_cursor; +    } +    // Remove SEARCH_START from flags to avoid getting stuck at one position.      searchflags &= ~SEARCH_START;    } @@ -4460,23 +4525,22 @@ static void nv_exmode(cmdarg_T *cap)    }  } -/* - * Handle a ":" command. - */ +/// Handle a ":" command and <Cmd>.  static void nv_colon(cmdarg_T *cap)  {    int old_p_im;    bool cmd_result; +  bool is_cmdkey = cap->cmdchar == K_COMMAND; -  if (VIsual_active) +  if (VIsual_active && !is_cmdkey) {      nv_operator(cap); -  else { +  } else {      if (cap->oap->op_type != OP_NOP) {        // Using ":" as a movement is characterwise exclusive.        cap->oap->motion_type = kMTCharWise;        cap->oap->inclusive = false; -    } else if (cap->count0) { -      /* translate "count:" into ":.,.+(count - 1)" */ +    } else if (cap->count0 && !is_cmdkey) { +      // translate "count:" into ":.,.+(count - 1)"        stuffcharReadbuff('.');        if (cap->count0 > 1) {          stuffReadbuff(",.+"); @@ -4490,9 +4554,9 @@ static void nv_colon(cmdarg_T *cap)      old_p_im = p_im; -    /* get a command line and execute it */ -    cmd_result = do_cmdline(NULL, getexline, NULL, -        cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0); +    // get a command line and execute it +    cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL, +                            cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);      /* If 'insertmode' changed, enter or exit Insert mode */      if (p_im != old_p_im) { @@ -4973,26 +5037,21 @@ static void nv_right(cmdarg_T *cap)      if ((!PAST_LINE && oneright() == false)          || (PAST_LINE && *get_cursor_pos_ptr() == NUL)          ) { -      /* -       *	  <Space> wraps to next line if 'whichwrap' has 's'. -       *	      'l' wraps to next line if 'whichwrap' has 'l'. -       * CURS_RIGHT wraps to next line if 'whichwrap' has '>'. -       */ -      if (       ((cap->cmdchar == ' ' -                   && vim_strchr(p_ww, 's') != NULL) -                  || (cap->cmdchar == 'l' -                      && vim_strchr(p_ww, 'l') != NULL) -                  || (cap->cmdchar == K_RIGHT -                      && vim_strchr(p_ww, '>') != NULL)) -                 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { -        /* When deleting we also count the NL as a character. -         * Set cap->oap->inclusive when last char in the line is -         * included, move to next line after that */ -        if (       cap->oap->op_type != OP_NOP -                   && !cap->oap->inclusive -                   && !lineempty(curwin->w_cursor.lnum)) +      //          <Space> wraps to next line if 'whichwrap' has 's'. +      //              'l' wraps to next line if 'whichwrap' has 'l'. +      // CURS_RIGHT wraps to next line if 'whichwrap' has '>'. +      if (((cap->cmdchar == ' ' && vim_strchr(p_ww, 's') != NULL) +           || (cap->cmdchar == 'l' && vim_strchr(p_ww, 'l') != NULL) +           || (cap->cmdchar == K_RIGHT && vim_strchr(p_ww, '>') != NULL)) +          && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { +        // When deleting we also count the NL as a character. +        // Set cap->oap->inclusive when last char in the line is +        // included, move to next line after that +        if (cap->oap->op_type != OP_NOP +            && !cap->oap->inclusive +            && !LINEEMPTY(curwin->w_cursor.lnum)) {            cap->oap->inclusive = true; -        else { +        } else {            ++curwin->w_cursor.lnum;            curwin->w_cursor.col = 0;            curwin->w_cursor.coladd = 0; @@ -5002,12 +5061,14 @@ static void nv_right(cmdarg_T *cap)          continue;        }        if (cap->oap->op_type == OP_NOP) { -        /* Only beep and flush if not moved at all */ -        if (n == cap->count1) +        // Only beep and flush if not moved at all +        if (n == cap->count1) {            beep_flush(); +        }        } else { -        if (!lineempty(curwin->w_cursor.lnum)) +        if (!LINEEMPTY(curwin->w_cursor.lnum)) {            cap->oap->inclusive = true; +        }        }        break;      } else if (PAST_LINE) { @@ -5065,13 +5126,12 @@ static void nv_left(cmdarg_T *cap)          coladvance((colnr_T)MAXCOL);          curwin->w_set_curswant = true; -        /* When the NL before the first char has to be deleted we -         * put the cursor on the NUL after the previous line. -         * This is a very special case, be careful! -         * Don't adjust op_end now, otherwise it won't work. */ -        if (       (cap->oap->op_type == OP_DELETE -                    || cap->oap->op_type == OP_CHANGE) -                   && !lineempty(curwin->w_cursor.lnum)) { +        // When the NL before the first char has to be deleted we +        // put the cursor on the NUL after the previous line. +        // This is a very special case, be careful! +        // Don't adjust op_end now, otherwise it won't work. +        if ((cap->oap->op_type == OP_DELETE || cap->oap->op_type == OP_CHANGE) +            && !LINEEMPTY(curwin->w_cursor.lnum)) {            char_u *cp = get_cursor_pos_ptr();            if (*cp != NUL) { @@ -5170,12 +5230,12 @@ static void nv_gotofile(cmdarg_T *cap)    if (ptr != NULL) {      // do autowrite if necessary -    if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf)) { +    if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !buf_hide(curbuf)) {        (void)autowrite(curbuf, false);      }      setpcmark();      (void)do_ecmd(0, ptr, NULL, NULL, ECMD_LAST, -        P_HID(curbuf) ? ECMD_HIDE : 0, curwin); +                  buf_hide(curbuf) ? ECMD_HIDE : 0, curwin);      if (cap->nchar == 'F' && lnum >= 0) {        curwin->w_cursor.lnum = lnum;        check_cursor_lnum(); @@ -5226,6 +5286,7 @@ static void nv_dollar(cmdarg_T *cap)  static void nv_search(cmdarg_T *cap)  {    oparg_T     *oap = cap->oap; +  pos_T save_cursor = curwin->w_cursor;    if (cap->cmdchar == '?' && cap->oap->op_type == OP_ROT13) {      /* Translate "g??" to "g?g?" */ @@ -5235,6 +5296,8 @@ static void nv_search(cmdarg_T *cap)      return;    } +  // When using 'incsearch' the cursor may be moved to set a different search +  // start position.    cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0);    if (cap->searchbuf == NULL) { @@ -5243,7 +5306,8 @@ static void nv_search(cmdarg_T *cap)    }    (void)normal_search(cap, cap->cmdchar, cap->searchbuf, -      (cap->arg ? 0 : SEARCH_MARK)); +                      (cap->arg || !equalpos(save_cursor, curwin->w_cursor)) +                      ? 0 : SEARCH_MARK);  }  /* @@ -5625,6 +5689,8 @@ static void nv_brackets(cmdarg_T *cap)                          cap->nchar == 's', false, NULL) == 0) {          clearopbeep(cap->oap);          break; +      } else { +        curwin->w_set_curswant = true;        }      if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped)        foldOpenCursor(); @@ -5794,10 +5860,13 @@ static void nv_replace(cmdarg_T *cap)      if (got_int)        reset_VIsual();      if (had_ctrl_v) { -      if (cap->nchar == '\r') -        cap->nchar = -1; -      else if (cap->nchar == '\n') -        cap->nchar = -2; +      // Use a special (negative) number to make a difference between a +      // literal CR or NL and a line break. +      if (cap->nchar == CAR) { +        cap->nchar = REPLACE_CR_NCHAR; +      } else if (cap->nchar == NL) { +        cap->nchar = REPLACE_NL_NCHAR; +      }      }      nv_operator(cap);      return; @@ -6034,10 +6103,11 @@ static void n_swapchar(cmdarg_T *cap)    pos_T startpos;    int did_change = 0; -  if (checkclearopq(cap->oap)) +  if (checkclearopq(cap->oap)) {      return; +  } -  if (lineempty(curwin->w_cursor.lnum) && vim_strchr(p_ww, '~') == NULL) { +  if (LINEEMPTY(curwin->w_cursor.lnum) && vim_strchr(p_ww, '~') == NULL) {      clearopbeep(cap->oap);      return;    } @@ -6200,15 +6270,18 @@ static void nv_gomark(cmdarg_T *cap)    } else      nv_cursormark(cap, cap->arg, pos); -  /* May need to clear the coladd that a mark includes. */ -  if (!virtual_active()) +  // May need to clear the coladd that a mark includes. +  if (!virtual_active()) {      curwin->w_cursor.coladd = 0; +  } +  check_cursor_col();    if (cap->oap->op_type == OP_NOP        && pos != NULL        && (pos == (pos_T *)-1 || !equalpos(old_cursor, *pos))        && (fdo_flags & FDO_MARK) -      && old_KeyTyped) +      && old_KeyTyped) {      foldOpenCursor(); +  }  }  /* @@ -7612,11 +7685,13 @@ static void nv_record(cmdarg_T *cap)      if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') {        stuffcharReadbuff(cap->nchar);        stuffcharReadbuff(K_CMDWIN); -    } else -    /* (stop) recording into a named register, unless executing a -     * register */ -    if (!Exec_reg && do_record(cap->nchar) == false) -      clearopbeep(cap->oap); +    } else { +      // (stop) recording into a named register, unless executing a +      // register. +      if (!Exec_reg && do_record(cap->nchar) == FAIL) { +        clearopbeep(cap->oap); +      } +    }    }  } @@ -7897,18 +7972,7 @@ static void nv_event(cmdarg_T *cap)    may_garbage_collect = false;    multiqueue_process_events(main_loop.events);    cap->retval |= CA_COMMAND_BUSY;       // don't call edit() now -} - -/// Trigger FocusGained event. -static void nv_focusgained(cmdarg_T *cap) -{ -  apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf); -} - -/// Trigger FocusLost event. -static void nv_focuslost(cmdarg_T *cap) -{ -  apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf); +  finish_op = false;  }  /* | 
