aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/normal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/normal.c')
-rw-r--r--src/nvim/normal.c276
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;
}
/*