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.c101
1 files changed, 74 insertions, 27 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 8fdc660b68..0bf93ee001 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2991,6 +2991,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:
@@ -3031,6 +3068,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
@@ -3042,30 +3080,40 @@ 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;
+ this_class = mb_get_class(ptr + col);
+ if (this_class != 0 && (i == 1 || this_class != 1)) {
+ break;
+ }
+ col += utfc_ptr2len(ptr + col);
+ }
+ // When starting on a ']' count it, so that we include the '['.
+ bn = ptr[col] == ']';
//
// 2. Back up to start of identifier/string.
//
// Remember class of character under cursor.
- this_class = mb_get_class(ptr + col);
+ 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))) {
+ && (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;
@@ -3096,21 +3144,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;