diff options
Diffstat (limited to 'src/nvim/search.c')
| -rw-r--r-- | src/nvim/search.c | 116 |
1 files changed, 95 insertions, 21 deletions
diff --git a/src/nvim/search.c b/src/nvim/search.c index cb461c9ef2..18a72524cb 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -918,7 +918,7 @@ static int first_submatch(regmmatch_T *rp) * Careful: If spats[0].off.line == TRUE and spats[0].off.off == 0 this * makes the movement linewise without moving the match position. * - * return 0 for failure, 1 for found, 2 for found and line offset added + * Return 0 for failure, 1 for found, 2 for found and line offset added. */ int do_search( oparg_T *oap, /* can be NULL */ @@ -1443,19 +1443,64 @@ static int check_prevcol(char_u *linep, int col, int ch, int *prevcol) } /* + * Raw string start is found at linep[startpos.col - 1]. + * Return true if the matching end can be found between startpos and endpos. + */ +static int find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos) +{ + char_u *p; + char_u *delim_copy; + size_t delim_len; + linenr_T lnum; + int found = false; + + for (p = linep + startpos->col + 1; *p && *p != '('; ++p) {} + + delim_len = (p - linep) - startpos->col - 1; + delim_copy = vim_strnsave(linep + startpos->col + 1, delim_len); + if (delim_copy == NULL) + return false; + for (lnum = startpos->lnum; lnum <= endpos->lnum; ++lnum) + { + char_u *line = ml_get(lnum); + + for (p = line + (lnum == startpos->lnum + ? startpos->col + 1 : 0); *p; ++p) + { + if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col) + break; + if (*p == ')' && p[delim_len + 1] == '"' + && STRNCMP(delim_copy, p + 1, delim_len) == 0) + { + found = true; + break; + } + } + if (found) + break; + } + xfree(delim_copy); + return found; +} + +/* * findmatchlimit -- find the matching paren or brace, if it exists within - * maxtravel lines of here. A maxtravel of 0 means search until falling off - * the edge of the file. + * maxtravel lines of the cursor. A maxtravel of 0 means search until falling + * off the edge of the file. * * "initc" is the character to find a match for. NUL means to find the - * character at or after the cursor. + * character at or after the cursor. Special values: + * '*' look for C-style comment / * + * '/' look for C-style comment / *, ignoring comment-end + * '#' look for preprocessor directives + * 'R' look for raw string start: R"delim(text)delim" (only backwards) * * flags: FM_BACKWARD search backwards (when initc is '/', '*' or '#') * FM_FORWARD search forwards (when initc is '/', '*' or '#') * FM_BLOCKSTOP stop at start/end of block ({ or } in column 0) * FM_SKIPCOMM skip comments (not implemented yet!) * - * "oap" is only used to set oap->motion_type for a linewise motion, it be + * "oap" is only used to set oap->motion_type for a linewise motion, it can be * NULL */ @@ -1465,8 +1510,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) int findc = 0; /* matching brace */ int c; int count = 0; /* cumulative number of braces */ - int backwards = FALSE; /* init for gcc */ - int inquote = FALSE; /* TRUE when inside quotes */ + int backwards = false; /* init for gcc */ + int raw_string = false; /* search for raw string */ + int inquote = false; /* true when inside quotes */ char_u *linep; /* pointer to current line */ char_u *ptr; int do_quotes; /* check for quotes in current line */ @@ -1506,22 +1552,22 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) * When '/' is used, we ignore running backwards into a star-slash, for * "[*" command, we just want to find any comment. */ - if (initc == '/' || initc == '*') { + if (initc == '/' || initc == '*' || initc == 'R') { comment_dir = dir; if (initc == '/') - ignore_cend = TRUE; - backwards = (dir == FORWARD) ? FALSE : TRUE; + ignore_cend = true; + backwards = (dir == FORWARD) ? false : true; + raw_string = (initc == 'R'); initc = NUL; } else if (initc != '#' && initc != NUL) { find_mps_values(&initc, &findc, &backwards, TRUE); if (findc == NUL) return NULL; - } - /* - * Either initc is '#', or no initc was given and we need to look under the - * cursor. - */ - else { + } else { + /* + * Either initc is '#', or no initc was given and we need to look + * under the cursor. + */ if (initc == '#') { hash_dir = dir; } else { @@ -1766,7 +1812,26 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) */ if (pos.col == 0) continue; - else if ( linep[pos.col - 1] == '/' + else if (raw_string) + { + if (linep[pos.col - 1] == 'R' + && linep[pos.col] == '"' + && vim_strchr(linep + pos.col + 1, '(') != NULL) + { + /* Possible start of raw string. Now that we have the + * delimiter we can check if it ends before where we + * started searching, or before the previously found + * raw string start. */ + if (!find_rawstring_end(linep, &pos, + count > 0 ? &match_pos : &curwin->w_cursor)) + { + count++; + match_pos = pos; + match_pos.col--; + } + linep = ml_get(pos.lnum); /* may have been released */ + } + } else if ( linep[pos.col - 1] == '/' && linep[pos.col] == '*' && (int)pos.col < comment_col) { count++; @@ -3193,6 +3258,7 @@ current_tagblock ( int do_include = include; bool save_p_ws = p_ws; int retval = FAIL; + int is_inclusive = true; p_ws = false; @@ -3287,9 +3353,16 @@ again: if (inc_cursor() < 0) break; } else { - /* Exclude the '<' of the end tag. */ - if (*get_cursor_pos_ptr() == '<') + char_u *c = get_cursor_pos_ptr(); + // Exclude the '<' of the end tag. + // If the closing tag is on new line, do not decrement cursor, but make + // operation exclusive, so that the linefeed will be selected + if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0) { + // do not decrement cursor + is_inclusive = false; + } else if (*c == '<') { dec_cursor(); + } } end_pos = curwin->w_cursor; @@ -3334,8 +3407,9 @@ again: * on an empty area. */ curwin->w_cursor = start_pos; oap->inclusive = false; - } else - oap->inclusive = true; + } else { + oap->inclusive = is_inclusive; + } } retval = OK; |