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.c237
1 files changed, 139 insertions, 98 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 570368991a..f87de52a82 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1269,7 +1269,8 @@ static void normal_redraw(NormalState *s)
xfree(p);
}
- if (need_fileinfo) { // show file info after redraw
+ // show fileinfo after redraw
+ if (need_fileinfo && !shortmess(SHM_FILEINFO)) {
fileinfo(false, true, false);
need_fileinfo = false;
}
@@ -1867,7 +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
+ FALLTHROUGH;
case OP_INDENT:
case OP_COLON:
@@ -2015,7 +2016,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
default:
clearopbeep(oap);
}
- virtual_op = MAYBE;
+ virtual_op = kNone;
if (!gui_yank) {
/*
* if 'sol' not set, go back to old column for some commands
@@ -2090,7 +2091,7 @@ static void op_colon(oparg_T *oap)
*/
static void op_function(oparg_T *oap)
{
- int save_virtual_op = virtual_op;
+ const TriState save_virtual_op = virtual_op;
if (*p_opfunc == NUL)
EMSG(_("E774: 'operatorfunc' is empty"));
@@ -2113,7 +2114,7 @@ static void op_function(oparg_T *oap)
// Reset virtual_op so that 'virtualedit' can be changed in the
// function.
- virtual_op = MAYBE;
+ virtual_op = kNone;
(void)call_func_retnr(p_opfunc, 1, argv, false);
@@ -2858,9 +2859,10 @@ static void find_start_of_word(pos_T *pos)
while (pos->col > 0) {
col = pos->col - 1;
- col -= (*mb_head_off)(line, line + col);
- if (get_mouse_class(line + col) != cclass)
+ col -= utf_head_off(line, line + col);
+ if (get_mouse_class(line + col) != cclass) {
break;
+ }
pos->col = col;
}
}
@@ -2877,8 +2879,8 @@ static void find_end_of_word(pos_T *pos)
line = ml_get(pos->lnum);
if (*p_sel == 'e' && pos->col > 0) {
- --pos->col;
- pos->col -= (*mb_head_off)(line, line + pos->col);
+ pos->col--;
+ pos->col -= utf_head_off(line, line + pos->col);
}
cclass = get_mouse_class(line + pos->col);
while (line[pos->col] != NUL) {
@@ -2990,6 +2992,43 @@ void reset_VIsual(void)
}
}
+// Check for a balloon-eval special item to include when searching for an
+// identifier. When "dir" is BACKWARD "ptr[-1]" must be valid!
+// Returns true if the character at "*ptr" should be included.
+// "dir" is FORWARD or BACKWARD, the direction of searching.
+// "*colp" is in/decremented if "ptr[-dir]" should also be included.
+// "bnp" points to a counter for square brackets.
+static bool find_is_eval_item(
+ const char_u *const ptr,
+ int *const colp,
+ int *const bnp,
+ const int dir)
+{
+ // Accept everything inside [].
+ if ((*ptr == ']' && dir == BACKWARD) || (*ptr == '[' && dir == FORWARD)) {
+ *bnp += 1;
+ }
+ if (*bnp > 0) {
+ if ((*ptr == '[' && dir == BACKWARD) || (*ptr == ']' && dir == FORWARD)) {
+ *bnp -= 1;
+ }
+ return true;
+ }
+
+ // skip over "s.var"
+ if (*ptr == '.') {
+ return true;
+ }
+
+ // two-character item: s->var
+ if (ptr[dir == BACKWARD ? 0 : 1] == '>'
+ && ptr[dir == BACKWARD ? -1 : 0] == '-') {
+ *colp += dir;
+ return true;
+ }
+ return false;
+}
+
/*
* Find the identifier under or to the right of the cursor.
* "find_type" can have one of three values:
@@ -3030,6 +3069,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol,
int this_class = 0;
int prev_class;
int prevcol;
+ int bn = 0; // bracket nesting
/*
* if i == 0: try to find an identifier
@@ -3041,71 +3081,62 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol,
* 1. skip to start of identifier/string
*/
col = startcol;
- if (has_mbyte) {
- while (ptr[col] != NUL) {
- this_class = mb_get_class(ptr + col);
- if (this_class != 0 && (i == 1 || this_class != 1))
- break;
- col += (*mb_ptr2len)(ptr + col);
+ while (ptr[col] != NUL) {
+ // Stop at a ']' to evaluate "a[x]".
+ if ((find_type & FIND_EVAL) && ptr[col] == ']') {
+ break;
}
- } else
- while (ptr[col] != NUL
- && (i == 0 ? !vim_iswordc(ptr[col]) : ascii_iswhite(ptr[col]))
- )
- ++col;
-
-
- /*
- * 2. Back up to start of identifier/string.
- */
- if (has_mbyte) {
- /* Remember class of character under cursor. */
this_class = mb_get_class(ptr + col);
- while (col > 0 && this_class != 0) {
- prevcol = col - 1 - (*mb_head_off)(ptr, ptr + col - 1);
- prev_class = mb_get_class(ptr + prevcol);
- if (this_class != prev_class
- && (i == 0
- || prev_class == 0
- || (find_type & FIND_IDENT))
- )
- break;
- col = prevcol;
+ if (this_class != 0 && (i == 1 || this_class != 1)) {
+ break;
}
+ col += utfc_ptr2len(ptr + col);
+ }
- /* If we don't want just any old string, or we've found an
- * identifier, stop searching. */
- if (this_class > 2)
- this_class = 2;
- if (!(find_type & FIND_STRING) || this_class == 2)
- break;
- } else {
- while (col > 0
- && ((i == 0
- ? vim_iswordc(ptr[col - 1])
- : (!ascii_iswhite(ptr[col - 1])
- && (!(find_type & FIND_IDENT)
- || !vim_iswordc(ptr[col - 1]))))
- ))
- --col;
+ // When starting on a ']' count it, so that we include the '['.
+ bn = ptr[col] == ']';
- /* If we don't want just any old string, or we've found an
- * identifier, stop searching. */
- if (!(find_type & FIND_STRING) || vim_iswordc(ptr[col]))
+ //
+ // 2. Back up to start of identifier/string.
+ //
+ // Remember class of character under cursor.
+ if ((find_type & FIND_EVAL) && ptr[col] == ']') {
+ this_class = mb_get_class((char_u *)"a");
+ } else {
+ this_class = mb_get_class(ptr + col);
+ }
+ while (col > 0 && this_class != 0) {
+ prevcol = col - 1 - utf_head_off(ptr, ptr + col - 1);
+ prev_class = mb_get_class(ptr + prevcol);
+ if (this_class != prev_class
+ && (i == 0
+ || prev_class == 0
+ || (find_type & FIND_IDENT))
+ && (!(find_type & FIND_EVAL)
+ || prevcol == 0
+ || !find_is_eval_item(ptr + prevcol, &prevcol, &bn, BACKWARD))) {
break;
+ }
+ col = prevcol;
+ }
+
+ // If we don't want just any old string, or we've found an
+ // identifier, stop searching.
+ if (this_class > 2) {
+ this_class = 2;
+ }
+ if (!(find_type & FIND_STRING) || this_class == 2) {
+ break;
}
}
- if (ptr[col] == NUL || (i == 0 && (
- has_mbyte ? this_class != 2 :
- !vim_iswordc(ptr[col])))) {
- /*
- * didn't find an identifier or string
- */
- if (find_type & FIND_STRING)
+ if (ptr[col] == NUL || (i == 0 && this_class != 2)) {
+ // Didn't find an identifier or string.
+ if (find_type & FIND_STRING) {
EMSG(_("E348: No string under cursor"));
- else
+ } else {
EMSG(_(e_noident));
+ }
return 0;
}
ptr += col;
@@ -3114,21 +3145,20 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol,
/*
* 3. Find the end if the identifier/string.
*/
+ bn = 0;
+ startcol -= col;
col = 0;
- if (has_mbyte) {
- /* Search for point of changing multibyte character class. */
- this_class = mb_get_class(ptr);
- while (ptr[col] != NUL
- && ((i == 0 ? mb_get_class(ptr + col) == this_class
- : mb_get_class(ptr + col) != 0)
- ))
- col += (*mb_ptr2len)(ptr + col);
- } else
- while ((i == 0 ? vim_iswordc(ptr[col])
- : (ptr[col] != NUL && !ascii_iswhite(ptr[col])))
- ) {
- ++col;
- }
+ // Search for point of changing multibyte character class.
+ this_class = mb_get_class(ptr);
+ while (ptr[col] != NUL
+ && ((i == 0
+ ? mb_get_class(ptr + col) == this_class
+ : mb_get_class(ptr + col) != 0)
+ || ((find_type & FIND_EVAL)
+ && col <= (int)startcol
+ && find_is_eval_item(ptr + col, &col, &bn, FORWARD)))) {
+ col += utfc_ptr2len(ptr + col);
+ }
assert(col >= 0);
return (size_t)col;
@@ -3994,8 +4024,12 @@ static void nv_mousescroll(cmdarg_T *cap)
row = mouse_row;
col = mouse_col;
- /* find the window at the pointer coordinates */
- curwin = mouse_find_win(&row, &col);
+ // find the window at the pointer coordinates
+ win_T *const wp = mouse_find_win(&row, &col);
+ if (wp == NULL) {
+ return;
+ }
+ curwin = wp;
curbuf = curwin->w_buffer;
}
@@ -4169,12 +4203,12 @@ dozet:
else
curwin->w_cursor.lnum = curwin->w_botline;
}
- /* FALLTHROUGH */
+ FALLTHROUGH;
case NL:
case CAR:
case K_KENTER:
beginline(BL_WHITE | BL_FIX);
- /* FALLTHROUGH */
+ FALLTHROUGH;
case 't': scroll_cursor_top(0, true);
redraw_later(VALID);
@@ -4183,7 +4217,7 @@ dozet:
/* "z." and "zz": put cursor in middle of screen */
case '.': beginline(BL_WHITE | BL_FIX);
- /* FALLTHROUGH */
+ FALLTHROUGH;
case 'z': scroll_cursor_halfway(true);
redraw_later(VALID);
@@ -4201,10 +4235,10 @@ dozet:
curwin->w_cursor.lnum = 1;
else
curwin->w_cursor.lnum = curwin->w_topline - 1;
- /* FALLTHROUGH */
+ FALLTHROUGH;
case '-':
beginline(BL_WHITE | BL_FIX);
- /* FALLTHROUGH */
+ FALLTHROUGH;
case 'b': scroll_cursor_bot(0, true);
redraw_later(VALID);
@@ -4214,7 +4248,7 @@ dozet:
/* "zH" - scroll screen right half-page */
case 'H':
cap->count1 *= curwin->w_width / 2;
- /* FALLTHROUGH */
+ FALLTHROUGH;
/* "zh" - scroll screen to the right */
case 'h':
@@ -4230,7 +4264,7 @@ dozet:
/* "zL" - scroll screen left half-page */
case 'L': cap->count1 *= curwin->w_width / 2;
- /* FALLTHROUGH */
+ FALLTHROUGH;
/* "zl" - scroll screen to the left */
case 'l':
@@ -4447,7 +4481,7 @@ dozet:
break;
}
undo = true;
- /*FALLTHROUGH*/
+ FALLTHROUGH;
case 'g': /* "zg": add good word to word list */
case 'w': /* "zw": add wrong word to word list */
@@ -4738,6 +4772,10 @@ static void nv_ident(cmdarg_T *cap)
assert(*kp != NUL); // option.c:do_set() should default to ":help" if empty.
bool kp_ex = (*kp == ':'); // 'keywordprg' is an ex command
bool kp_help = (STRCMP(kp, ":he") == 0 || STRCMP(kp, ":help") == 0);
+ if (kp_help && *skipwhite(ptr) == NUL) {
+ EMSG(_(e_noident)); // found white space only
+ return;
+ }
size_t buf_size = n * 2 + 30 + STRLEN(kp);
char *buf = xmalloc(buf_size);
buf[0] = NUL;
@@ -5005,7 +5043,10 @@ static void nv_scroll(cmdarg_T *cap)
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
}
- cursor_correct(); /* correct for 'so' */
+ // Correct for 'so', except when an operator is pending.
+ if (cap->oap->op_type == OP_NOP) {
+ cursor_correct();
+ }
beginline(BL_SOL | BL_FIX);
}
@@ -6257,7 +6298,7 @@ static void nv_gomark(cmdarg_T *cap)
pos_T *pos;
int c;
pos_T old_cursor = curwin->w_cursor;
- int old_KeyTyped = KeyTyped; /* getting file may reset it */
+ const bool old_KeyTyped = KeyTyped; // getting file may reset it
if (cap->cmdchar == 'g')
c = cap->extra_char;
@@ -6294,7 +6335,7 @@ static void nv_pcmark(cmdarg_T *cap)
{
pos_T *pos;
linenr_T lnum = curwin->w_cursor.lnum;
- int old_KeyTyped = KeyTyped; /* getting file may reset it */
+ const bool old_KeyTyped = KeyTyped; // getting file may reset it
if (!checkclearopq(cap->oap)) {
if (cap->cmdchar == 'g')
@@ -6459,8 +6500,8 @@ void may_start_select(int c)
*/
static void n_start_visual_mode(int c)
{
- /* Check for redraw before changing the state. */
- conceal_check_cursur_line();
+ // Check for redraw before changing the state.
+ conceal_check_cursor_line();
VIsual_mode = c;
VIsual_active = true;
@@ -6477,8 +6518,8 @@ static void n_start_visual_mode(int c)
foldAdjustVisual();
setmouse();
- /* Check for redraw after changing the state. */
- conceal_check_cursur_line();
+ // Check for redraw after changing the state.
+ conceal_check_cursor_line();
if (p_smd && msg_silent == 0)
redraw_cmdline = true; /* show visual mode later */
@@ -6623,7 +6664,7 @@ static void nv_g_cmd(cmdarg_T *cap)
*/
case K_BS:
cap->nchar = Ctrl_H;
- /* FALLTHROUGH */
+ FALLTHROUGH;
case 'h':
case 'H':
case Ctrl_H:
@@ -6689,7 +6730,7 @@ static void nv_g_cmd(cmdarg_T *cap)
*/
case '^':
flag = true;
- /* FALLTHROUGH */
+ FALLTHROUGH;
case '0':
case 'm':
@@ -6867,7 +6908,7 @@ static void nv_g_cmd(cmdarg_T *cap)
/* "g'm" and "g`m": jump to mark without setting pcmark */
case '\'':
cap->arg = true;
- /*FALLTHROUGH*/
+ FALLTHROUGH;
case '`':
nv_gomark(cap);
break;
@@ -6925,7 +6966,7 @@ static void nv_g_cmd(cmdarg_T *cap)
case 'q':
case 'w':
oap->cursor_start = curwin->w_cursor;
- /*FALLTHROUGH*/
+ FALLTHROUGH;
case '~':
case 'u':
case 'U':