1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 /* 10 * search.c: code for normal mode searching commands 11 */ 12 13 #include "vim.h" 14 15 #ifdef FEAT_EVAL 16 static void set_vv_searchforward(void); 17 static int first_submatch(regmmatch_T *rp); 18 #endif 19 static int check_linecomment(char_u *line); 20 #ifdef FEAT_FIND_ID 21 static void show_pat_in_path(char_u *, int, 22 int, int, FILE *, linenr_T *, long); 23 #endif 24 static void search_stat(int dirc, pos_T *pos, int show_top_bot_msg, char_u *msgbuf, int recompute); 25 26 /* 27 * This file contains various searching-related routines. These fall into 28 * three groups: 29 * 1. string searches (for /, ?, n, and N) 30 * 2. character searches within a single line (for f, F, t, T, etc) 31 * 3. "other" kinds of searches like the '%' command, and 'word' searches. 32 */ 33 34 /* 35 * String searches 36 * 37 * The string search functions are divided into two levels: 38 * lowest: searchit(); uses an pos_T for starting position and found match. 39 * Highest: do_search(); uses curwin->w_cursor; calls searchit(). 40 * 41 * The last search pattern is remembered for repeating the same search. 42 * This pattern is shared between the :g, :s, ? and / commands. 43 * This is in search_regcomp(). 44 * 45 * The actual string matching is done using a heavily modified version of 46 * Henry Spencer's regular expression library. See regexp.c. 47 */ 48 49 /* 50 * Two search patterns are remembered: One for the :substitute command and 51 * one for other searches. last_idx points to the one that was used the last 52 * time. 53 */ 54 static spat_T spats[2] = 55 { 56 {NULL, TRUE, FALSE, {'/', 0, 0, 0L}}, // last used search pat 57 {NULL, TRUE, FALSE, {'/', 0, 0, 0L}} // last used substitute pat 58 }; 59 60 static int last_idx = 0; // index in spats[] for RE_LAST 61 62 static char_u lastc[2] = {NUL, NUL}; // last character searched for 63 static int lastcdir = FORWARD; // last direction of character search 64 static int last_t_cmd = TRUE; // last search t_cmd 65 static char_u lastc_bytes[MB_MAXBYTES + 1]; 66 static int lastc_bytelen = 1; // >1 for multi-byte char 67 68 // copy of spats[], for keeping the search patterns while executing autocmds 69 static spat_T saved_spats[2]; 70 # ifdef FEAT_SEARCH_EXTRA 71 static int saved_spats_last_idx = 0; 72 static int saved_spats_no_hlsearch = 0; 73 # endif 74 75 static char_u *mr_pattern = NULL; // pattern used by search_regcomp() 76 #ifdef FEAT_RIGHTLEFT 77 static int mr_pattern_alloced = FALSE; // mr_pattern was allocated 78 #endif 79 80 #ifdef FEAT_FIND_ID 81 /* 82 * Type used by find_pattern_in_path() to remember which included files have 83 * been searched already. 84 */ 85 typedef struct SearchedFile 86 { 87 FILE *fp; // File pointer 88 char_u *name; // Full name of file 89 linenr_T lnum; // Line we were up to in file 90 int matched; // Found a match in this file 91 } SearchedFile; 92 #endif 93 94 /* 95 * translate search pattern for vim_regcomp() 96 * 97 * pat_save == RE_SEARCH: save pat in spats[RE_SEARCH].pat (normal search cmd) 98 * pat_save == RE_SUBST: save pat in spats[RE_SUBST].pat (:substitute command) 99 * pat_save == RE_BOTH: save pat in both patterns (:global command) 100 * pat_use == RE_SEARCH: use previous search pattern if "pat" is NULL 101 * pat_use == RE_SUBST: use previous substitute pattern if "pat" is NULL 102 * pat_use == RE_LAST: use last used pattern if "pat" is NULL 103 * options & SEARCH_HIS: put search string in history 104 * options & SEARCH_KEEP: keep previous search pattern 105 * 106 * returns FAIL if failed, OK otherwise. 107 */ 108 int 109 search_regcomp( 110 char_u *pat, 111 int pat_save, 112 int pat_use, 113 int options, 114 regmmatch_T *regmatch) // return: pattern and ignore-case flag 115 { 116 int magic; 117 int i; 118 119 rc_did_emsg = FALSE; 120 magic = p_magic; 121 122 /* 123 * If no pattern given, use a previously defined pattern. 124 */ 125 if (pat == NULL || *pat == NUL) 126 { 127 if (pat_use == RE_LAST) 128 i = last_idx; 129 else 130 i = pat_use; 131 if (spats[i].pat == NULL) // pattern was never defined 132 { 133 if (pat_use == RE_SUBST) 134 emsg(_(e_nopresub)); 135 else 136 emsg(_(e_noprevre)); 137 rc_did_emsg = TRUE; 138 return FAIL; 139 } 140 pat = spats[i].pat; 141 magic = spats[i].magic; 142 no_smartcase = spats[i].no_scs; 143 } 144 else if (options & SEARCH_HIS) // put new pattern in history 145 add_to_history(HIST_SEARCH, pat, TRUE, NUL); 146 147 #ifdef FEAT_RIGHTLEFT 148 if (mr_pattern_alloced) 149 { 150 vim_free(mr_pattern); 151 mr_pattern_alloced = FALSE; 152 } 153 154 if (curwin->w_p_rl && *curwin->w_p_rlc == 's') 155 { 156 char_u *rev_pattern; 157 158 rev_pattern = reverse_text(pat); 159 if (rev_pattern == NULL) 160 mr_pattern = pat; // out of memory, keep normal pattern. 161 else 162 { 163 mr_pattern = rev_pattern; 164 mr_pattern_alloced = TRUE; 165 } 166 } 167 else 168 #endif 169 mr_pattern = pat; 170 171 /* 172 * Save the currently used pattern in the appropriate place, 173 * unless the pattern should not be remembered. 174 */ 175 if (!(options & SEARCH_KEEP) && !cmdmod.keeppatterns) 176 { 177 // search or global command 178 if (pat_save == RE_SEARCH || pat_save == RE_BOTH) 179 save_re_pat(RE_SEARCH, pat, magic); 180 // substitute or global command 181 if (pat_save == RE_SUBST || pat_save == RE_BOTH) 182 save_re_pat(RE_SUBST, pat, magic); 183 } 184 185 regmatch->rmm_ic = ignorecase(pat); 186 regmatch->rmm_maxcol = 0; 187 regmatch->regprog = vim_regcomp(pat, magic ? RE_MAGIC : 0); 188 if (regmatch->regprog == NULL) 189 return FAIL; 190 return OK; 191 } 192 193 /* 194 * Get search pattern used by search_regcomp(). 195 */ 196 char_u * 197 get_search_pat(void) 198 { 199 return mr_pattern; 200 } 201 202 #if defined(FEAT_RIGHTLEFT) || defined(PROTO) 203 /* 204 * Reverse text into allocated memory. 205 * Returns the allocated string, NULL when out of memory. 206 */ 207 char_u * 208 reverse_text(char_u *s) 209 { 210 unsigned len; 211 unsigned s_i, rev_i; 212 char_u *rev; 213 214 /* 215 * Reverse the pattern. 216 */ 217 len = (unsigned)STRLEN(s); 218 rev = alloc(len + 1); 219 if (rev != NULL) 220 { 221 rev_i = len; 222 for (s_i = 0; s_i < len; ++s_i) 223 { 224 if (has_mbyte) 225 { 226 int mb_len; 227 228 mb_len = (*mb_ptr2len)(s + s_i); 229 rev_i -= mb_len; 230 mch_memmove(rev + rev_i, s + s_i, mb_len); 231 s_i += mb_len - 1; 232 } 233 else 234 rev[--rev_i] = s[s_i]; 235 236 } 237 rev[len] = NUL; 238 } 239 return rev; 240 } 241 #endif 242 243 void 244 save_re_pat(int idx, char_u *pat, int magic) 245 { 246 if (spats[idx].pat != pat) 247 { 248 vim_free(spats[idx].pat); 249 spats[idx].pat = vim_strsave(pat); 250 spats[idx].magic = magic; 251 spats[idx].no_scs = no_smartcase; 252 last_idx = idx; 253 #ifdef FEAT_SEARCH_EXTRA 254 // If 'hlsearch' set and search pat changed: need redraw. 255 if (p_hls) 256 redraw_all_later(SOME_VALID); 257 set_no_hlsearch(FALSE); 258 #endif 259 } 260 } 261 262 /* 263 * Save the search patterns, so they can be restored later. 264 * Used before/after executing autocommands and user functions. 265 */ 266 static int save_level = 0; 267 268 void 269 save_search_patterns(void) 270 { 271 if (save_level++ == 0) 272 { 273 saved_spats[0] = spats[0]; 274 if (spats[0].pat != NULL) 275 saved_spats[0].pat = vim_strsave(spats[0].pat); 276 saved_spats[1] = spats[1]; 277 if (spats[1].pat != NULL) 278 saved_spats[1].pat = vim_strsave(spats[1].pat); 279 #ifdef FEAT_SEARCH_EXTRA 280 saved_spats_last_idx = last_idx; 281 saved_spats_no_hlsearch = no_hlsearch; 282 #endif 283 } 284 } 285 286 void 287 restore_search_patterns(void) 288 { 289 if (--save_level == 0) 290 { 291 vim_free(spats[0].pat); 292 spats[0] = saved_spats[0]; 293 #if defined(FEAT_EVAL) 294 set_vv_searchforward(); 295 #endif 296 vim_free(spats[1].pat); 297 spats[1] = saved_spats[1]; 298 #ifdef FEAT_SEARCH_EXTRA 299 last_idx = saved_spats_last_idx; 300 set_no_hlsearch(saved_spats_no_hlsearch); 301 #endif 302 } 303 } 304 305 #if defined(EXITFREE) || defined(PROTO) 306 void 307 free_search_patterns(void) 308 { 309 vim_free(spats[0].pat); 310 vim_free(spats[1].pat); 311 312 # ifdef FEAT_RIGHTLEFT 313 if (mr_pattern_alloced) 314 { 315 vim_free(mr_pattern); 316 mr_pattern_alloced = FALSE; 317 mr_pattern = NULL; 318 } 319 # endif 320 } 321 #endif 322 323 #ifdef FEAT_SEARCH_EXTRA 324 // copy of spats[RE_SEARCH], for keeping the search patterns while incremental 325 // searching 326 static spat_T saved_last_search_spat; 327 static int did_save_last_search_spat = 0; 328 static int saved_last_idx = 0; 329 static int saved_no_hlsearch = 0; 330 331 /* 332 * Save and restore the search pattern for incremental highlight search 333 * feature. 334 * 335 * It's similar to but different from save_search_patterns() and 336 * restore_search_patterns(), because the search pattern must be restored when 337 * canceling incremental searching even if it's called inside user functions. 338 */ 339 void 340 save_last_search_pattern(void) 341 { 342 if (did_save_last_search_spat != 0) 343 iemsg("did_save_last_search_spat is not zero"); 344 else 345 ++did_save_last_search_spat; 346 347 saved_last_search_spat = spats[RE_SEARCH]; 348 if (spats[RE_SEARCH].pat != NULL) 349 saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat); 350 saved_last_idx = last_idx; 351 saved_no_hlsearch = no_hlsearch; 352 } 353 354 void 355 restore_last_search_pattern(void) 356 { 357 if (did_save_last_search_spat != 1) 358 { 359 iemsg("did_save_last_search_spat is not one"); 360 return; 361 } 362 --did_save_last_search_spat; 363 364 vim_free(spats[RE_SEARCH].pat); 365 spats[RE_SEARCH] = saved_last_search_spat; 366 saved_last_search_spat.pat = NULL; 367 # if defined(FEAT_EVAL) 368 set_vv_searchforward(); 369 # endif 370 last_idx = saved_last_idx; 371 set_no_hlsearch(saved_no_hlsearch); 372 } 373 374 char_u * 375 last_search_pattern(void) 376 { 377 return spats[RE_SEARCH].pat; 378 } 379 #endif 380 381 /* 382 * Return TRUE when case should be ignored for search pattern "pat". 383 * Uses the 'ignorecase' and 'smartcase' options. 384 */ 385 int 386 ignorecase(char_u *pat) 387 { 388 return ignorecase_opt(pat, p_ic, p_scs); 389 } 390 391 /* 392 * As ignorecase() put pass the "ic" and "scs" flags. 393 */ 394 int 395 ignorecase_opt(char_u *pat, int ic_in, int scs) 396 { 397 int ic = ic_in; 398 399 if (ic && !no_smartcase && scs 400 && !(ctrl_x_mode_not_default() && curbuf->b_p_inf)) 401 ic = !pat_has_uppercase(pat); 402 no_smartcase = FALSE; 403 404 return ic; 405 } 406 407 /* 408 * Return TRUE if pattern "pat" has an uppercase character. 409 */ 410 int 411 pat_has_uppercase(char_u *pat) 412 { 413 char_u *p = pat; 414 415 while (*p != NUL) 416 { 417 int l; 418 419 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) 420 { 421 if (enc_utf8 && utf_isupper(utf_ptr2char(p))) 422 return TRUE; 423 p += l; 424 } 425 else if (*p == '\\') 426 { 427 if (p[1] == '_' && p[2] != NUL) // skip "\_X" 428 p += 3; 429 else if (p[1] == '%' && p[2] != NUL) // skip "\%X" 430 p += 3; 431 else if (p[1] != NUL) // skip "\X" 432 p += 2; 433 else 434 p += 1; 435 } 436 else if (MB_ISUPPER(*p)) 437 return TRUE; 438 else 439 ++p; 440 } 441 return FALSE; 442 } 443 444 #if defined(FEAT_EVAL) || defined(PROTO) 445 char_u * 446 last_csearch(void) 447 { 448 return lastc_bytes; 449 } 450 451 int 452 last_csearch_forward(void) 453 { 454 return lastcdir == FORWARD; 455 } 456 457 int 458 last_csearch_until(void) 459 { 460 return last_t_cmd == TRUE; 461 } 462 463 void 464 set_last_csearch(int c, char_u *s UNUSED, int len UNUSED) 465 { 466 *lastc = c; 467 lastc_bytelen = len; 468 if (len) 469 memcpy(lastc_bytes, s, len); 470 else 471 CLEAR_FIELD(lastc_bytes); 472 } 473 #endif 474 475 void 476 set_csearch_direction(int cdir) 477 { 478 lastcdir = cdir; 479 } 480 481 void 482 set_csearch_until(int t_cmd) 483 { 484 last_t_cmd = t_cmd; 485 } 486 487 char_u * 488 last_search_pat(void) 489 { 490 return spats[last_idx].pat; 491 } 492 493 /* 494 * Reset search direction to forward. For "gd" and "gD" commands. 495 */ 496 void 497 reset_search_dir(void) 498 { 499 spats[0].off.dir = '/'; 500 #if defined(FEAT_EVAL) 501 set_vv_searchforward(); 502 #endif 503 } 504 505 #if defined(FEAT_EVAL) || defined(FEAT_VIMINFO) 506 /* 507 * Set the last search pattern. For ":let @/ =" and viminfo. 508 * Also set the saved search pattern, so that this works in an autocommand. 509 */ 510 void 511 set_last_search_pat( 512 char_u *s, 513 int idx, 514 int magic, 515 int setlast) 516 { 517 vim_free(spats[idx].pat); 518 // An empty string means that nothing should be matched. 519 if (*s == NUL) 520 spats[idx].pat = NULL; 521 else 522 spats[idx].pat = vim_strsave(s); 523 spats[idx].magic = magic; 524 spats[idx].no_scs = FALSE; 525 spats[idx].off.dir = '/'; 526 #if defined(FEAT_EVAL) 527 set_vv_searchforward(); 528 #endif 529 spats[idx].off.line = FALSE; 530 spats[idx].off.end = FALSE; 531 spats[idx].off.off = 0; 532 if (setlast) 533 last_idx = idx; 534 if (save_level) 535 { 536 vim_free(saved_spats[idx].pat); 537 saved_spats[idx] = spats[0]; 538 if (spats[idx].pat == NULL) 539 saved_spats[idx].pat = NULL; 540 else 541 saved_spats[idx].pat = vim_strsave(spats[idx].pat); 542 # ifdef FEAT_SEARCH_EXTRA 543 saved_spats_last_idx = last_idx; 544 # endif 545 } 546 # ifdef FEAT_SEARCH_EXTRA 547 // If 'hlsearch' set and search pat changed: need redraw. 548 if (p_hls && idx == last_idx && !no_hlsearch) 549 redraw_all_later(SOME_VALID); 550 # endif 551 } 552 #endif 553 554 #ifdef FEAT_SEARCH_EXTRA 555 /* 556 * Get a regexp program for the last used search pattern. 557 * This is used for highlighting all matches in a window. 558 * Values returned in regmatch->regprog and regmatch->rmm_ic. 559 */ 560 void 561 last_pat_prog(regmmatch_T *regmatch) 562 { 563 if (spats[last_idx].pat == NULL) 564 { 565 regmatch->regprog = NULL; 566 return; 567 } 568 ++emsg_off; // So it doesn't beep if bad expr 569 (void)search_regcomp((char_u *)"", 0, last_idx, SEARCH_KEEP, regmatch); 570 --emsg_off; 571 } 572 #endif 573 574 /* 575 * Lowest level search function. 576 * Search for 'count'th occurrence of pattern "pat" in direction "dir". 577 * Start at position "pos" and return the found position in "pos". 578 * 579 * if (options & SEARCH_MSG) == 0 don't give any messages 580 * if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages 581 * if (options & SEARCH_MSG) == SEARCH_MSG give all messages 582 * if (options & SEARCH_HIS) put search pattern in history 583 * if (options & SEARCH_END) return position at end of match 584 * if (options & SEARCH_START) accept match at pos itself 585 * if (options & SEARCH_KEEP) keep previous search pattern 586 * if (options & SEARCH_FOLD) match only once in a closed fold 587 * if (options & SEARCH_PEEK) check for typed char, cancel search 588 * if (options & SEARCH_COL) start at pos->col instead of zero 589 * 590 * Return FAIL (zero) for failure, non-zero for success. 591 * When FEAT_EVAL is defined, returns the index of the first matching 592 * subpattern plus one; one if there was none. 593 */ 594 int 595 searchit( 596 win_T *win, // window to search in; can be NULL for a 597 // buffer without a window! 598 buf_T *buf, 599 pos_T *pos, 600 pos_T *end_pos, // set to end of the match, unless NULL 601 int dir, 602 char_u *pat, 603 long count, 604 int options, 605 int pat_use, // which pattern to use when "pat" is empty 606 searchit_arg_T *extra_arg) // optional extra arguments, can be NULL 607 { 608 int found; 609 linenr_T lnum; // no init to shut up Apollo cc 610 colnr_T col; 611 regmmatch_T regmatch; 612 char_u *ptr; 613 colnr_T matchcol; 614 lpos_T endpos; 615 lpos_T matchpos; 616 int loop; 617 pos_T start_pos; 618 int at_first_line; 619 int extra_col; 620 int start_char_len; 621 int match_ok; 622 long nmatched; 623 int submatch = 0; 624 int first_match = TRUE; 625 int called_emsg_before = called_emsg; 626 #ifdef FEAT_SEARCH_EXTRA 627 int break_loop = FALSE; 628 #endif 629 linenr_T stop_lnum = 0; // stop after this line number when != 0 630 #ifdef FEAT_RELTIME 631 proftime_T *tm = NULL; // timeout limit or NULL 632 int *timed_out = NULL; // set when timed out or NULL 633 #endif 634 635 if (extra_arg != NULL) 636 { 637 stop_lnum = extra_arg->sa_stop_lnum; 638 #ifdef FEAT_RELTIME 639 tm = extra_arg->sa_tm; 640 timed_out = &extra_arg->sa_timed_out; 641 #endif 642 } 643 644 if (search_regcomp(pat, RE_SEARCH, pat_use, 645 (options & (SEARCH_HIS + SEARCH_KEEP)), ®match) == FAIL) 646 { 647 if ((options & SEARCH_MSG) && !rc_did_emsg) 648 semsg(_("E383: Invalid search string: %s"), mr_pattern); 649 return FAIL; 650 } 651 652 /* 653 * find the string 654 */ 655 do // loop for count 656 { 657 // When not accepting a match at the start position set "extra_col" to 658 // a non-zero value. Don't do that when starting at MAXCOL, since 659 // MAXCOL + 1 is zero. 660 if (pos->col == MAXCOL) 661 start_char_len = 0; 662 // Watch out for the "col" being MAXCOL - 2, used in a closed fold. 663 else if (has_mbyte 664 && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count 665 && pos->col < MAXCOL - 2) 666 { 667 ptr = ml_get_buf(buf, pos->lnum, FALSE); 668 if ((int)STRLEN(ptr) <= pos->col) 669 start_char_len = 1; 670 else 671 start_char_len = (*mb_ptr2len)(ptr + pos->col); 672 } 673 else 674 start_char_len = 1; 675 if (dir == FORWARD) 676 { 677 if (options & SEARCH_START) 678 extra_col = 0; 679 else 680 extra_col = start_char_len; 681 } 682 else 683 { 684 if (options & SEARCH_START) 685 extra_col = start_char_len; 686 else 687 extra_col = 0; 688 } 689 690 start_pos = *pos; // remember start pos for detecting no match 691 found = 0; // default: not found 692 at_first_line = TRUE; // default: start in first line 693 if (pos->lnum == 0) // correct lnum for when starting in line 0 694 { 695 pos->lnum = 1; 696 pos->col = 0; 697 at_first_line = FALSE; // not in first line now 698 } 699 700 /* 701 * Start searching in current line, unless searching backwards and 702 * we're in column 0. 703 * If we are searching backwards, in column 0, and not including the 704 * current position, gain some efficiency by skipping back a line. 705 * Otherwise begin the search in the current line. 706 */ 707 if (dir == BACKWARD && start_pos.col == 0 708 && (options & SEARCH_START) == 0) 709 { 710 lnum = pos->lnum - 1; 711 at_first_line = FALSE; 712 } 713 else 714 lnum = pos->lnum; 715 716 for (loop = 0; loop <= 1; ++loop) // loop twice if 'wrapscan' set 717 { 718 for ( ; lnum > 0 && lnum <= buf->b_ml.ml_line_count; 719 lnum += dir, at_first_line = FALSE) 720 { 721 // Stop after checking "stop_lnum", if it's set. 722 if (stop_lnum != 0 && (dir == FORWARD 723 ? lnum > stop_lnum : lnum < stop_lnum)) 724 break; 725 #ifdef FEAT_RELTIME 726 // Stop after passing the "tm" time limit. 727 if (tm != NULL && profile_passed_limit(tm)) 728 break; 729 #endif 730 731 /* 732 * Look for a match somewhere in line "lnum". 733 */ 734 col = at_first_line && (options & SEARCH_COL) ? pos->col 735 : (colnr_T)0; 736 nmatched = vim_regexec_multi(®match, win, buf, 737 lnum, col, 738 #ifdef FEAT_RELTIME 739 tm, timed_out 740 #else 741 NULL, NULL 742 #endif 743 ); 744 // Abort searching on an error (e.g., out of stack). 745 if (called_emsg > called_emsg_before 746 #ifdef FEAT_RELTIME 747 || (timed_out != NULL && *timed_out) 748 #endif 749 ) 750 break; 751 if (nmatched > 0) 752 { 753 // match may actually be in another line when using \zs 754 matchpos = regmatch.startpos[0]; 755 endpos = regmatch.endpos[0]; 756 #ifdef FEAT_EVAL 757 submatch = first_submatch(®match); 758 #endif 759 // "lnum" may be past end of buffer for "\n\zs". 760 if (lnum + matchpos.lnum > buf->b_ml.ml_line_count) 761 ptr = (char_u *)""; 762 else 763 ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE); 764 765 /* 766 * Forward search in the first line: match should be after 767 * the start position. If not, continue at the end of the 768 * match (this is vi compatible) or on the next char. 769 */ 770 if (dir == FORWARD && at_first_line) 771 { 772 match_ok = TRUE; 773 /* 774 * When the match starts in a next line it's certainly 775 * past the start position. 776 * When match lands on a NUL the cursor will be put 777 * one back afterwards, compare with that position, 778 * otherwise "/$" will get stuck on end of line. 779 */ 780 while (matchpos.lnum == 0 781 && ((options & SEARCH_END) && first_match 782 ? (nmatched == 1 783 && (int)endpos.col - 1 784 < (int)start_pos.col + extra_col) 785 : ((int)matchpos.col 786 - (ptr[matchpos.col] == NUL) 787 < (int)start_pos.col + extra_col))) 788 { 789 /* 790 * If vi-compatible searching, continue at the end 791 * of the match, otherwise continue one position 792 * forward. 793 */ 794 if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) 795 { 796 if (nmatched > 1) 797 { 798 // end is in next line, thus no match in 799 // this line 800 match_ok = FALSE; 801 break; 802 } 803 matchcol = endpos.col; 804 // for empty match: advance one char 805 if (matchcol == matchpos.col 806 && ptr[matchcol] != NUL) 807 { 808 if (has_mbyte) 809 matchcol += 810 (*mb_ptr2len)(ptr + matchcol); 811 else 812 ++matchcol; 813 } 814 } 815 else 816 { 817 matchcol = matchpos.col; 818 if (ptr[matchcol] != NUL) 819 { 820 if (has_mbyte) 821 matchcol += (*mb_ptr2len)(ptr 822 + matchcol); 823 else 824 ++matchcol; 825 } 826 } 827 if (matchcol == 0 && (options & SEARCH_START)) 828 break; 829 if (ptr[matchcol] == NUL 830 || (nmatched = vim_regexec_multi(®match, 831 win, buf, lnum + matchpos.lnum, 832 matchcol, 833 #ifdef FEAT_RELTIME 834 tm, timed_out 835 #else 836 NULL, NULL 837 #endif 838 )) == 0) 839 { 840 match_ok = FALSE; 841 break; 842 } 843 matchpos = regmatch.startpos[0]; 844 endpos = regmatch.endpos[0]; 845 # ifdef FEAT_EVAL 846 submatch = first_submatch(®match); 847 # endif 848 849 // Need to get the line pointer again, a 850 // multi-line search may have made it invalid. 851 ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE); 852 } 853 if (!match_ok) 854 continue; 855 } 856 if (dir == BACKWARD) 857 { 858 /* 859 * Now, if there are multiple matches on this line, 860 * we have to get the last one. Or the last one before 861 * the cursor, if we're on that line. 862 * When putting the new cursor at the end, compare 863 * relative to the end of the match. 864 */ 865 match_ok = FALSE; 866 for (;;) 867 { 868 // Remember a position that is before the start 869 // position, we use it if it's the last match in 870 // the line. Always accept a position after 871 // wrapping around. 872 if (loop 873 || ((options & SEARCH_END) 874 ? (lnum + regmatch.endpos[0].lnum 875 < start_pos.lnum 876 || (lnum + regmatch.endpos[0].lnum 877 == start_pos.lnum 878 && (int)regmatch.endpos[0].col - 1 879 < (int)start_pos.col 880 + extra_col)) 881 : (lnum + regmatch.startpos[0].lnum 882 < start_pos.lnum 883 || (lnum + regmatch.startpos[0].lnum 884 == start_pos.lnum 885 && (int)regmatch.startpos[0].col 886 < (int)start_pos.col 887 + extra_col)))) 888 { 889 match_ok = TRUE; 890 matchpos = regmatch.startpos[0]; 891 endpos = regmatch.endpos[0]; 892 # ifdef FEAT_EVAL 893 submatch = first_submatch(®match); 894 # endif 895 } 896 else 897 break; 898 899 /* 900 * We found a valid match, now check if there is 901 * another one after it. 902 * If vi-compatible searching, continue at the end 903 * of the match, otherwise continue one position 904 * forward. 905 */ 906 if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) 907 { 908 if (nmatched > 1) 909 break; 910 matchcol = endpos.col; 911 // for empty match: advance one char 912 if (matchcol == matchpos.col 913 && ptr[matchcol] != NUL) 914 { 915 if (has_mbyte) 916 matchcol += 917 (*mb_ptr2len)(ptr + matchcol); 918 else 919 ++matchcol; 920 } 921 } 922 else 923 { 924 // Stop when the match is in a next line. 925 if (matchpos.lnum > 0) 926 break; 927 matchcol = matchpos.col; 928 if (ptr[matchcol] != NUL) 929 { 930 if (has_mbyte) 931 matchcol += 932 (*mb_ptr2len)(ptr + matchcol); 933 else 934 ++matchcol; 935 } 936 } 937 if (ptr[matchcol] == NUL 938 || (nmatched = vim_regexec_multi(®match, 939 win, buf, lnum + matchpos.lnum, 940 matchcol, 941 #ifdef FEAT_RELTIME 942 tm, timed_out 943 #else 944 NULL, NULL 945 #endif 946 )) == 0) 947 { 948 #ifdef FEAT_RELTIME 949 // If the search timed out, we did find a match 950 // but it might be the wrong one, so that's not 951 // OK. 952 if (timed_out != NULL && *timed_out) 953 match_ok = FALSE; 954 #endif 955 break; 956 } 957 958 // Need to get the line pointer again, a 959 // multi-line search may have made it invalid. 960 ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE); 961 } 962 963 /* 964 * If there is only a match after the cursor, skip 965 * this match. 966 */ 967 if (!match_ok) 968 continue; 969 } 970 971 // With the SEARCH_END option move to the last character 972 // of the match. Don't do it for an empty match, end 973 // should be same as start then. 974 if ((options & SEARCH_END) && !(options & SEARCH_NOOF) 975 && !(matchpos.lnum == endpos.lnum 976 && matchpos.col == endpos.col)) 977 { 978 // For a match in the first column, set the position 979 // on the NUL in the previous line. 980 pos->lnum = lnum + endpos.lnum; 981 pos->col = endpos.col; 982 if (endpos.col == 0) 983 { 984 if (pos->lnum > 1) // just in case 985 { 986 --pos->lnum; 987 pos->col = (colnr_T)STRLEN(ml_get_buf(buf, 988 pos->lnum, FALSE)); 989 } 990 } 991 else 992 { 993 --pos->col; 994 if (has_mbyte 995 && pos->lnum <= buf->b_ml.ml_line_count) 996 { 997 ptr = ml_get_buf(buf, pos->lnum, FALSE); 998 pos->col -= (*mb_head_off)(ptr, ptr + pos->col); 999 } 1000 } 1001 if (end_pos != NULL) 1002 { 1003 end_pos->lnum = lnum + matchpos.lnum; 1004 end_pos->col = matchpos.col; 1005 } 1006 } 1007 else 1008 { 1009 pos->lnum = lnum + matchpos.lnum; 1010 pos->col = matchpos.col; 1011 if (end_pos != NULL) 1012 { 1013 end_pos->lnum = lnum + endpos.lnum; 1014 end_pos->col = endpos.col; 1015 } 1016 } 1017 pos->coladd = 0; 1018 if (end_pos != NULL) 1019 end_pos->coladd = 0; 1020 found = 1; 1021 first_match = FALSE; 1022 1023 // Set variables used for 'incsearch' highlighting. 1024 search_match_lines = endpos.lnum - matchpos.lnum; 1025 search_match_endcol = endpos.col; 1026 break; 1027 } 1028 line_breakcheck(); // stop if ctrl-C typed 1029 if (got_int) 1030 break; 1031 1032 #ifdef FEAT_SEARCH_EXTRA 1033 // Cancel searching if a character was typed. Used for 1034 // 'incsearch'. Don't check too often, that would slowdown 1035 // searching too much. 1036 if ((options & SEARCH_PEEK) 1037 && ((lnum - pos->lnum) & 0x3f) == 0 1038 && char_avail()) 1039 { 1040 break_loop = TRUE; 1041 break; 1042 } 1043 #endif 1044 1045 if (loop && lnum == start_pos.lnum) 1046 break; // if second loop, stop where started 1047 } 1048 at_first_line = FALSE; 1049 1050 /* 1051 * Stop the search if wrapscan isn't set, "stop_lnum" is 1052 * specified, after an interrupt, after a match and after looping 1053 * twice. 1054 */ 1055 if (!p_ws || stop_lnum != 0 || got_int 1056 || called_emsg > called_emsg_before 1057 #ifdef FEAT_RELTIME 1058 || (timed_out != NULL && *timed_out) 1059 #endif 1060 #ifdef FEAT_SEARCH_EXTRA 1061 || break_loop 1062 #endif 1063 || found || loop) 1064 break; 1065 1066 /* 1067 * If 'wrapscan' is set we continue at the other end of the file. 1068 * If 'shortmess' does not contain 's', we give a message. 1069 * This message is also remembered in keep_msg for when the screen 1070 * is redrawn. The keep_msg is cleared whenever another message is 1071 * written. 1072 */ 1073 if (dir == BACKWARD) // start second loop at the other end 1074 lnum = buf->b_ml.ml_line_count; 1075 else 1076 lnum = 1; 1077 if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG)) 1078 give_warning((char_u *)_(dir == BACKWARD 1079 ? top_bot_msg : bot_top_msg), TRUE); 1080 if (extra_arg != NULL) 1081 extra_arg->sa_wrapped = TRUE; 1082 } 1083 if (got_int || called_emsg > called_emsg_before 1084 #ifdef FEAT_RELTIME 1085 || (timed_out != NULL && *timed_out) 1086 #endif 1087 #ifdef FEAT_SEARCH_EXTRA 1088 || break_loop 1089 #endif 1090 ) 1091 break; 1092 } 1093 while (--count > 0 && found); // stop after count matches or no match 1094 1095 vim_regfree(regmatch.regprog); 1096 1097 if (!found) // did not find it 1098 { 1099 if (got_int) 1100 emsg(_(e_interr)); 1101 else if ((options & SEARCH_MSG) == SEARCH_MSG) 1102 { 1103 if (p_ws) 1104 semsg(_(e_patnotf2), mr_pattern); 1105 else if (lnum == 0) 1106 semsg(_("E384: search hit TOP without match for: %s"), 1107 mr_pattern); 1108 else 1109 semsg(_("E385: search hit BOTTOM without match for: %s"), 1110 mr_pattern); 1111 } 1112 return FAIL; 1113 } 1114 1115 // A pattern like "\n\zs" may go past the last line. 1116 if (pos->lnum > buf->b_ml.ml_line_count) 1117 { 1118 pos->lnum = buf->b_ml.ml_line_count; 1119 pos->col = (int)STRLEN(ml_get_buf(buf, pos->lnum, FALSE)); 1120 if (pos->col > 0) 1121 --pos->col; 1122 } 1123 1124 return submatch + 1; 1125 } 1126 1127 #ifdef FEAT_EVAL 1128 void 1129 set_search_direction(int cdir) 1130 { 1131 spats[0].off.dir = cdir; 1132 } 1133 1134 static void 1135 set_vv_searchforward(void) 1136 { 1137 set_vim_var_nr(VV_SEARCHFORWARD, (long)(spats[0].off.dir == '/')); 1138 } 1139 1140 /* 1141 * Return the number of the first subpat that matched. 1142 * Return zero if none of them matched. 1143 */ 1144 static int 1145 first_submatch(regmmatch_T *rp) 1146 { 1147 int submatch; 1148 1149 for (submatch = 1; ; ++submatch) 1150 { 1151 if (rp->startpos[submatch].lnum >= 0) 1152 break; 1153 if (submatch == 9) 1154 { 1155 submatch = 0; 1156 break; 1157 } 1158 } 1159 return submatch; 1160 } 1161 #endif 1162 1163 /* 1164 * Highest level string search function. 1165 * Search for the 'count'th occurrence of pattern 'pat' in direction 'dirc' 1166 * If 'dirc' is 0: use previous dir. 1167 * If 'pat' is NULL or empty : use previous string. 1168 * If 'options & SEARCH_REV' : go in reverse of previous dir. 1169 * If 'options & SEARCH_ECHO': echo the search command and handle options 1170 * If 'options & SEARCH_MSG' : may give error message 1171 * If 'options & SEARCH_OPT' : interpret optional flags 1172 * If 'options & SEARCH_HIS' : put search pattern in history 1173 * If 'options & SEARCH_NOOF': don't add offset to position 1174 * If 'options & SEARCH_MARK': set previous context mark 1175 * If 'options & SEARCH_KEEP': keep previous search pattern 1176 * If 'options & SEARCH_START': accept match at curpos itself 1177 * If 'options & SEARCH_PEEK': check for typed char, cancel search 1178 * 1179 * Careful: If spats[0].off.line == TRUE and spats[0].off.off == 0 this 1180 * makes the movement linewise without moving the match position. 1181 * 1182 * Return 0 for failure, 1 for found, 2 for found and line offset added. 1183 */ 1184 int 1185 do_search( 1186 oparg_T *oap, // can be NULL 1187 int dirc, // '/' or '?' 1188 int search_delim, // the delimiter for the search, e.g. '%' in s%regex%replacement% 1189 char_u *pat, 1190 long count, 1191 int options, 1192 searchit_arg_T *sia) // optional arguments or NULL 1193 { 1194 pos_T pos; // position of the last match 1195 char_u *searchstr; 1196 soffset_T old_off; 1197 int retval; // Return value 1198 char_u *p; 1199 long c; 1200 char_u *dircp; 1201 char_u *strcopy = NULL; 1202 char_u *ps; 1203 char_u *msgbuf = NULL; 1204 size_t len; 1205 int has_offset = FALSE; 1206 #define SEARCH_STAT_BUF_LEN 12 1207 1208 /* 1209 * A line offset is not remembered, this is vi compatible. 1210 */ 1211 if (spats[0].off.line && vim_strchr(p_cpo, CPO_LINEOFF) != NULL) 1212 { 1213 spats[0].off.line = FALSE; 1214 spats[0].off.off = 0; 1215 } 1216 1217 /* 1218 * Save the values for when (options & SEARCH_KEEP) is used. 1219 * (there is no "if ()" around this because gcc wants them initialized) 1220 */ 1221 old_off = spats[0].off; 1222 1223 pos = curwin->w_cursor; // start searching at the cursor position 1224 1225 /* 1226 * Find out the direction of the search. 1227 */ 1228 if (dirc == 0) 1229 dirc = spats[0].off.dir; 1230 else 1231 { 1232 spats[0].off.dir = dirc; 1233 #if defined(FEAT_EVAL) 1234 set_vv_searchforward(); 1235 #endif 1236 } 1237 if (options & SEARCH_REV) 1238 { 1239 #ifdef MSWIN 1240 // There is a bug in the Visual C++ 2.2 compiler which means that 1241 // dirc always ends up being '/' 1242 dirc = (dirc == '/') ? '?' : '/'; 1243 #else 1244 if (dirc == '/') 1245 dirc = '?'; 1246 else 1247 dirc = '/'; 1248 #endif 1249 } 1250 1251 #ifdef FEAT_FOLDING 1252 // If the cursor is in a closed fold, don't find another match in the same 1253 // fold. 1254 if (dirc == '/') 1255 { 1256 if (hasFolding(pos.lnum, NULL, &pos.lnum)) 1257 pos.col = MAXCOL - 2; // avoid overflow when adding 1 1258 } 1259 else 1260 { 1261 if (hasFolding(pos.lnum, &pos.lnum, NULL)) 1262 pos.col = 0; 1263 } 1264 #endif 1265 1266 #ifdef FEAT_SEARCH_EXTRA 1267 /* 1268 * Turn 'hlsearch' highlighting back on. 1269 */ 1270 if (no_hlsearch && !(options & SEARCH_KEEP)) 1271 { 1272 redraw_all_later(SOME_VALID); 1273 set_no_hlsearch(FALSE); 1274 } 1275 #endif 1276 1277 /* 1278 * Repeat the search when pattern followed by ';', e.g. "/foo/;?bar". 1279 */ 1280 for (;;) 1281 { 1282 int show_top_bot_msg = FALSE; 1283 1284 searchstr = pat; 1285 dircp = NULL; 1286 // use previous pattern 1287 if (pat == NULL || *pat == NUL || *pat == search_delim) 1288 { 1289 if (spats[RE_SEARCH].pat == NULL) // no previous pattern 1290 { 1291 searchstr = spats[RE_SUBST].pat; 1292 if (searchstr == NULL) 1293 { 1294 emsg(_(e_noprevre)); 1295 retval = 0; 1296 goto end_do_search; 1297 } 1298 } 1299 else 1300 { 1301 // make search_regcomp() use spats[RE_SEARCH].pat 1302 searchstr = (char_u *)""; 1303 } 1304 } 1305 1306 if (pat != NULL && *pat != NUL) // look for (new) offset 1307 { 1308 /* 1309 * Find end of regular expression. 1310 * If there is a matching '/' or '?', toss it. 1311 */ 1312 ps = strcopy; 1313 p = skip_regexp_ex(pat, search_delim, (int)p_magic, &strcopy, NULL); 1314 if (strcopy != ps) 1315 { 1316 // made a copy of "pat" to change "\?" to "?" 1317 searchcmdlen += (int)(STRLEN(pat) - STRLEN(strcopy)); 1318 pat = strcopy; 1319 searchstr = strcopy; 1320 } 1321 if (*p == search_delim) 1322 { 1323 dircp = p; // remember where we put the NUL 1324 *p++ = NUL; 1325 } 1326 spats[0].off.line = FALSE; 1327 spats[0].off.end = FALSE; 1328 spats[0].off.off = 0; 1329 /* 1330 * Check for a line offset or a character offset. 1331 * For get_address (echo off) we don't check for a character 1332 * offset, because it is meaningless and the 's' could be a 1333 * substitute command. 1334 */ 1335 if (*p == '+' || *p == '-' || VIM_ISDIGIT(*p)) 1336 spats[0].off.line = TRUE; 1337 else if ((options & SEARCH_OPT) && 1338 (*p == 'e' || *p == 's' || *p == 'b')) 1339 { 1340 if (*p == 'e') // end 1341 spats[0].off.end = SEARCH_END; 1342 ++p; 1343 } 1344 if (VIM_ISDIGIT(*p) || *p == '+' || *p == '-') // got an offset 1345 { 1346 // 'nr' or '+nr' or '-nr' 1347 if (VIM_ISDIGIT(*p) || VIM_ISDIGIT(*(p + 1))) 1348 spats[0].off.off = atol((char *)p); 1349 else if (*p == '-') // single '-' 1350 spats[0].off.off = -1; 1351 else // single '+' 1352 spats[0].off.off = 1; 1353 ++p; 1354 while (VIM_ISDIGIT(*p)) // skip number 1355 ++p; 1356 } 1357 1358 // compute length of search command for get_address() 1359 searchcmdlen += (int)(p - pat); 1360 1361 pat = p; // put pat after search command 1362 } 1363 1364 if ((options & SEARCH_ECHO) && messaging() && 1365 !msg_silent && 1366 (!cmd_silent || !shortmess(SHM_SEARCHCOUNT))) 1367 { 1368 char_u *trunc; 1369 char_u off_buf[40]; 1370 size_t off_len = 0; 1371 1372 // Compute msg_row early. 1373 msg_start(); 1374 1375 // Get the offset, so we know how long it is. 1376 if (!cmd_silent && 1377 (spats[0].off.line || spats[0].off.end || spats[0].off.off)) 1378 { 1379 p = off_buf; 1380 *p++ = dirc; 1381 if (spats[0].off.end) 1382 *p++ = 'e'; 1383 else if (!spats[0].off.line) 1384 *p++ = 's'; 1385 if (spats[0].off.off > 0 || spats[0].off.line) 1386 *p++ = '+'; 1387 *p = NUL; 1388 if (spats[0].off.off != 0 || spats[0].off.line) 1389 sprintf((char *)p, "%ld", spats[0].off.off); 1390 off_len = STRLEN(off_buf); 1391 } 1392 1393 if (*searchstr == NUL) 1394 p = spats[0].pat; 1395 else 1396 p = searchstr; 1397 1398 if (!shortmess(SHM_SEARCHCOUNT) || cmd_silent) 1399 { 1400 // Reserve enough space for the search pattern + offset + 1401 // search stat. Use all the space available, so that the 1402 // search state is right aligned. If there is not enough space 1403 // msg_strtrunc() will shorten in the middle. 1404 if (msg_scrolled != 0 && !cmd_silent) 1405 // Use all the columns. 1406 len = (int)(Rows - msg_row) * Columns - 1; 1407 else 1408 // Use up to 'showcmd' column. 1409 len = (int)(Rows - msg_row - 1) * Columns + sc_col - 1; 1410 if (len < STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3) 1411 len = STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3; 1412 } 1413 else 1414 // Reserve enough space for the search pattern + offset. 1415 len = STRLEN(p) + off_len + 3; 1416 1417 vim_free(msgbuf); 1418 msgbuf = alloc(len); 1419 if (msgbuf != NULL) 1420 { 1421 vim_memset(msgbuf, ' ', len); 1422 msgbuf[len - 1] = NUL; 1423 // do not fill the msgbuf buffer, if cmd_silent is set, leave it 1424 // empty for the search_stat feature. 1425 if (!cmd_silent) 1426 { 1427 msgbuf[0] = dirc; 1428 1429 if (enc_utf8 && utf_iscomposing(utf_ptr2char(p))) 1430 { 1431 // Use a space to draw the composing char on. 1432 msgbuf[1] = ' '; 1433 mch_memmove(msgbuf + 2, p, STRLEN(p)); 1434 } 1435 else 1436 mch_memmove(msgbuf + 1, p, STRLEN(p)); 1437 if (off_len > 0) 1438 mch_memmove(msgbuf + STRLEN(p) + 1, off_buf, off_len); 1439 1440 trunc = msg_strtrunc(msgbuf, TRUE); 1441 if (trunc != NULL) 1442 { 1443 vim_free(msgbuf); 1444 msgbuf = trunc; 1445 } 1446 1447 #ifdef FEAT_RIGHTLEFT 1448 // The search pattern could be shown on the right in rightleft 1449 // mode, but the 'ruler' and 'showcmd' area use it too, thus 1450 // it would be blanked out again very soon. Show it on the 1451 // left, but do reverse the text. 1452 if (curwin->w_p_rl && *curwin->w_p_rlc == 's') 1453 { 1454 char_u *r; 1455 size_t pat_len; 1456 1457 r = reverse_text(msgbuf); 1458 if (r != NULL) 1459 { 1460 vim_free(msgbuf); 1461 msgbuf = r; 1462 // move reversed text to beginning of buffer 1463 while (*r != NUL && *r == ' ') 1464 r++; 1465 pat_len = msgbuf + STRLEN(msgbuf) - r; 1466 mch_memmove(msgbuf, r, pat_len); 1467 // overwrite old text 1468 if ((size_t)(r - msgbuf) >= pat_len) 1469 vim_memset(r, ' ', pat_len); 1470 else 1471 vim_memset(msgbuf + pat_len, ' ', r - msgbuf); 1472 } 1473 } 1474 #endif 1475 msg_outtrans(msgbuf); 1476 msg_clr_eos(); 1477 msg_check(); 1478 1479 gotocmdline(FALSE); 1480 out_flush(); 1481 msg_nowait = TRUE; // don't wait for this message 1482 } 1483 } 1484 } 1485 1486 /* 1487 * If there is a character offset, subtract it from the current 1488 * position, so we don't get stuck at "?pat?e+2" or "/pat/s-2". 1489 * Skip this if pos.col is near MAXCOL (closed fold). 1490 * This is not done for a line offset, because then we would not be vi 1491 * compatible. 1492 */ 1493 if (!spats[0].off.line && spats[0].off.off && pos.col < MAXCOL - 2) 1494 { 1495 if (spats[0].off.off > 0) 1496 { 1497 for (c = spats[0].off.off; c; --c) 1498 if (decl(&pos) == -1) 1499 break; 1500 if (c) // at start of buffer 1501 { 1502 pos.lnum = 0; // allow lnum == 0 here 1503 pos.col = MAXCOL; 1504 } 1505 } 1506 else 1507 { 1508 for (c = spats[0].off.off; c; ++c) 1509 if (incl(&pos) == -1) 1510 break; 1511 if (c) // at end of buffer 1512 { 1513 pos.lnum = curbuf->b_ml.ml_line_count + 1; 1514 pos.col = 0; 1515 } 1516 } 1517 } 1518 1519 c = searchit(curwin, curbuf, &pos, NULL, 1520 dirc == '/' ? FORWARD : BACKWARD, 1521 searchstr, count, spats[0].off.end + (options & 1522 (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS 1523 + SEARCH_MSG + SEARCH_START 1524 + ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF))), 1525 RE_LAST, sia); 1526 1527 if (dircp != NULL) 1528 *dircp = search_delim; // restore second '/' or '?' for normal_cmd() 1529 1530 if (!shortmess(SHM_SEARCH) 1531 && ((dirc == '/' && LT_POS(pos, curwin->w_cursor)) 1532 || (dirc == '?' && LT_POS(curwin->w_cursor, pos)))) 1533 show_top_bot_msg = TRUE; 1534 1535 if (c == FAIL) 1536 { 1537 retval = 0; 1538 goto end_do_search; 1539 } 1540 if (spats[0].off.end && oap != NULL) 1541 oap->inclusive = TRUE; // 'e' includes last character 1542 1543 retval = 1; // pattern found 1544 1545 /* 1546 * Add character and/or line offset 1547 */ 1548 if (!(options & SEARCH_NOOF) || (pat != NULL && *pat == ';')) 1549 { 1550 pos_T org_pos = pos; 1551 1552 if (spats[0].off.line) // Add the offset to the line number. 1553 { 1554 c = pos.lnum + spats[0].off.off; 1555 if (c < 1) 1556 pos.lnum = 1; 1557 else if (c > curbuf->b_ml.ml_line_count) 1558 pos.lnum = curbuf->b_ml.ml_line_count; 1559 else 1560 pos.lnum = c; 1561 pos.col = 0; 1562 1563 retval = 2; // pattern found, line offset added 1564 } 1565 else if (pos.col < MAXCOL - 2) // just in case 1566 { 1567 // to the right, check for end of file 1568 c = spats[0].off.off; 1569 if (c > 0) 1570 { 1571 while (c-- > 0) 1572 if (incl(&pos) == -1) 1573 break; 1574 } 1575 // to the left, check for start of file 1576 else 1577 { 1578 while (c++ < 0) 1579 if (decl(&pos) == -1) 1580 break; 1581 } 1582 } 1583 if (!EQUAL_POS(pos, org_pos)) 1584 has_offset = TRUE; 1585 } 1586 1587 // Show [1/15] if 'S' is not in 'shortmess'. 1588 if ((options & SEARCH_ECHO) 1589 && messaging() 1590 && !msg_silent 1591 && c != FAIL 1592 && !shortmess(SHM_SEARCHCOUNT) 1593 && msgbuf != NULL) 1594 search_stat(dirc, &pos, show_top_bot_msg, msgbuf, 1595 (count != 1 || has_offset)); 1596 1597 /* 1598 * The search command can be followed by a ';' to do another search. 1599 * For example: "/pat/;/foo/+3;?bar" 1600 * This is like doing another search command, except: 1601 * - The remembered direction '/' or '?' is from the first search. 1602 * - When an error happens the cursor isn't moved at all. 1603 * Don't do this when called by get_address() (it handles ';' itself). 1604 */ 1605 if (!(options & SEARCH_OPT) || pat == NULL || *pat != ';') 1606 break; 1607 1608 dirc = *++pat; 1609 search_delim = dirc; 1610 if (dirc != '?' && dirc != '/') 1611 { 1612 retval = 0; 1613 emsg(_("E386: Expected '?' or '/' after ';'")); 1614 goto end_do_search; 1615 } 1616 ++pat; 1617 } 1618 1619 if (options & SEARCH_MARK) 1620 setpcmark(); 1621 curwin->w_cursor = pos; 1622 curwin->w_set_curswant = TRUE; 1623 1624 end_do_search: 1625 if ((options & SEARCH_KEEP) || cmdmod.keeppatterns) 1626 spats[0].off = old_off; 1627 vim_free(strcopy); 1628 vim_free(msgbuf); 1629 1630 return retval; 1631 } 1632 1633 /* 1634 * search_for_exact_line(buf, pos, dir, pat) 1635 * 1636 * Search for a line starting with the given pattern (ignoring leading 1637 * white-space), starting from pos and going in direction "dir". "pos" will 1638 * contain the position of the match found. Blank lines match only if 1639 * ADDING is set. If p_ic is set then the pattern must be in lowercase. 1640 * Return OK for success, or FAIL if no line found. 1641 */ 1642 int 1643 search_for_exact_line( 1644 buf_T *buf, 1645 pos_T *pos, 1646 int dir, 1647 char_u *pat) 1648 { 1649 linenr_T start = 0; 1650 char_u *ptr; 1651 char_u *p; 1652 1653 if (buf->b_ml.ml_line_count == 0) 1654 return FAIL; 1655 for (;;) 1656 { 1657 pos->lnum += dir; 1658 if (pos->lnum < 1) 1659 { 1660 if (p_ws) 1661 { 1662 pos->lnum = buf->b_ml.ml_line_count; 1663 if (!shortmess(SHM_SEARCH)) 1664 give_warning((char_u *)_(top_bot_msg), TRUE); 1665 } 1666 else 1667 { 1668 pos->lnum = 1; 1669 break; 1670 } 1671 } 1672 else if (pos->lnum > buf->b_ml.ml_line_count) 1673 { 1674 if (p_ws) 1675 { 1676 pos->lnum = 1; 1677 if (!shortmess(SHM_SEARCH)) 1678 give_warning((char_u *)_(bot_top_msg), TRUE); 1679 } 1680 else 1681 { 1682 pos->lnum = 1; 1683 break; 1684 } 1685 } 1686 if (pos->lnum == start) 1687 break; 1688 if (start == 0) 1689 start = pos->lnum; 1690 ptr = ml_get_buf(buf, pos->lnum, FALSE); 1691 p = skipwhite(ptr); 1692 pos->col = (colnr_T) (p - ptr); 1693 1694 // when adding lines the matching line may be empty but it is not 1695 // ignored because we are interested in the next line -- Acevedo 1696 if ((compl_cont_status & CONT_ADDING) 1697 && !(compl_cont_status & CONT_SOL)) 1698 { 1699 if ((p_ic ? MB_STRICMP(p, pat) : STRCMP(p, pat)) == 0) 1700 return OK; 1701 } 1702 else if (*p != NUL) // ignore empty lines 1703 { // expanding lines or words 1704 if ((p_ic ? MB_STRNICMP(p, pat, compl_length) 1705 : STRNCMP(p, pat, compl_length)) == 0) 1706 return OK; 1707 } 1708 } 1709 return FAIL; 1710 } 1711 1712 /* 1713 * Character Searches 1714 */ 1715 1716 /* 1717 * Search for a character in a line. If "t_cmd" is FALSE, move to the 1718 * position of the character, otherwise move to just before the char. 1719 * Do this "cap->count1" times. 1720 * Return FAIL or OK. 1721 */ 1722 int 1723 searchc(cmdarg_T *cap, int t_cmd) 1724 { 1725 int c = cap->nchar; // char to search for 1726 int dir = cap->arg; // TRUE for searching forward 1727 long count = cap->count1; // repeat count 1728 int col; 1729 char_u *p; 1730 int len; 1731 int stop = TRUE; 1732 1733 if (c != NUL) // normal search: remember args for repeat 1734 { 1735 if (!KeyStuffed) // don't remember when redoing 1736 { 1737 *lastc = c; 1738 set_csearch_direction(dir); 1739 set_csearch_until(t_cmd); 1740 lastc_bytelen = (*mb_char2bytes)(c, lastc_bytes); 1741 if (cap->ncharC1 != 0) 1742 { 1743 lastc_bytelen += (*mb_char2bytes)(cap->ncharC1, 1744 lastc_bytes + lastc_bytelen); 1745 if (cap->ncharC2 != 0) 1746 lastc_bytelen += (*mb_char2bytes)(cap->ncharC2, 1747 lastc_bytes + lastc_bytelen); 1748 } 1749 } 1750 } 1751 else // repeat previous search 1752 { 1753 if (*lastc == NUL && lastc_bytelen == 1) 1754 return FAIL; 1755 if (dir) // repeat in opposite direction 1756 dir = -lastcdir; 1757 else 1758 dir = lastcdir; 1759 t_cmd = last_t_cmd; 1760 c = *lastc; 1761 // For multi-byte re-use last lastc_bytes[] and lastc_bytelen. 1762 1763 // Force a move of at least one char, so ";" and "," will move the 1764 // cursor, even if the cursor is right in front of char we are looking 1765 // at. 1766 if (vim_strchr(p_cpo, CPO_SCOLON) == NULL && count == 1 && t_cmd) 1767 stop = FALSE; 1768 } 1769 1770 if (dir == BACKWARD) 1771 cap->oap->inclusive = FALSE; 1772 else 1773 cap->oap->inclusive = TRUE; 1774 1775 p = ml_get_curline(); 1776 col = curwin->w_cursor.col; 1777 len = (int)STRLEN(p); 1778 1779 while (count--) 1780 { 1781 if (has_mbyte) 1782 { 1783 for (;;) 1784 { 1785 if (dir > 0) 1786 { 1787 col += (*mb_ptr2len)(p + col); 1788 if (col >= len) 1789 return FAIL; 1790 } 1791 else 1792 { 1793 if (col == 0) 1794 return FAIL; 1795 col -= (*mb_head_off)(p, p + col - 1) + 1; 1796 } 1797 if (lastc_bytelen == 1) 1798 { 1799 if (p[col] == c && stop) 1800 break; 1801 } 1802 else if (STRNCMP(p + col, lastc_bytes, lastc_bytelen) == 0 1803 && stop) 1804 break; 1805 stop = TRUE; 1806 } 1807 } 1808 else 1809 { 1810 for (;;) 1811 { 1812 if ((col += dir) < 0 || col >= len) 1813 return FAIL; 1814 if (p[col] == c && stop) 1815 break; 1816 stop = TRUE; 1817 } 1818 } 1819 } 1820 1821 if (t_cmd) 1822 { 1823 // backup to before the character (possibly double-byte) 1824 col -= dir; 1825 if (has_mbyte) 1826 { 1827 if (dir < 0) 1828 // Landed on the search char which is lastc_bytelen long 1829 col += lastc_bytelen - 1; 1830 else 1831 // To previous char, which may be multi-byte. 1832 col -= (*mb_head_off)(p, p + col); 1833 } 1834 } 1835 curwin->w_cursor.col = col; 1836 1837 return OK; 1838 } 1839 1840 /* 1841 * "Other" Searches 1842 */ 1843 1844 /* 1845 * findmatch - find the matching paren or brace 1846 * 1847 * Improvement over vi: Braces inside quotes are ignored. 1848 */ 1849 pos_T * 1850 findmatch(oparg_T *oap, int initc) 1851 { 1852 return findmatchlimit(oap, initc, 0, 0); 1853 } 1854 1855 /* 1856 * Return TRUE if the character before "linep[col]" equals "ch". 1857 * Return FALSE if "col" is zero. 1858 * Update "*prevcol" to the column of the previous character, unless "prevcol" 1859 * is NULL. 1860 * Handles multibyte string correctly. 1861 */ 1862 static int 1863 check_prevcol( 1864 char_u *linep, 1865 int col, 1866 int ch, 1867 int *prevcol) 1868 { 1869 --col; 1870 if (col > 0 && has_mbyte) 1871 col -= (*mb_head_off)(linep, linep + col); 1872 if (prevcol) 1873 *prevcol = col; 1874 return (col >= 0 && linep[col] == ch) ? TRUE : FALSE; 1875 } 1876 1877 /* 1878 * Raw string start is found at linep[startpos.col - 1]. 1879 * Return TRUE if the matching end can be found between startpos and endpos. 1880 */ 1881 static int 1882 find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos) 1883 { 1884 char_u *p; 1885 char_u *delim_copy; 1886 size_t delim_len; 1887 linenr_T lnum; 1888 int found = FALSE; 1889 1890 for (p = linep + startpos->col + 1; *p && *p != '('; ++p) 1891 ; 1892 delim_len = (p - linep) - startpos->col - 1; 1893 delim_copy = vim_strnsave(linep + startpos->col + 1, (int)delim_len); 1894 if (delim_copy == NULL) 1895 return FALSE; 1896 for (lnum = startpos->lnum; lnum <= endpos->lnum; ++lnum) 1897 { 1898 char_u *line = ml_get(lnum); 1899 1900 for (p = line + (lnum == startpos->lnum 1901 ? startpos->col + 1 : 0); *p; ++p) 1902 { 1903 if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col) 1904 break; 1905 if (*p == ')' && p[delim_len + 1] == '"' 1906 && STRNCMP(delim_copy, p + 1, delim_len) == 0) 1907 { 1908 found = TRUE; 1909 break; 1910 } 1911 } 1912 if (found) 1913 break; 1914 } 1915 vim_free(delim_copy); 1916 return found; 1917 } 1918 1919 /* 1920 * Check matchpairs option for "*initc". 1921 * If there is a match set "*initc" to the matching character and "*findc" to 1922 * the opposite character. Set "*backwards" to the direction. 1923 * When "switchit" is TRUE swap the direction. 1924 */ 1925 static void 1926 find_mps_values( 1927 int *initc, 1928 int *findc, 1929 int *backwards, 1930 int switchit) 1931 { 1932 char_u *ptr; 1933 1934 ptr = curbuf->b_p_mps; 1935 while (*ptr != NUL) 1936 { 1937 if (has_mbyte) 1938 { 1939 char_u *prev; 1940 1941 if (mb_ptr2char(ptr) == *initc) 1942 { 1943 if (switchit) 1944 { 1945 *findc = *initc; 1946 *initc = mb_ptr2char(ptr + mb_ptr2len(ptr) + 1); 1947 *backwards = TRUE; 1948 } 1949 else 1950 { 1951 *findc = mb_ptr2char(ptr + mb_ptr2len(ptr) + 1); 1952 *backwards = FALSE; 1953 } 1954 return; 1955 } 1956 prev = ptr; 1957 ptr += mb_ptr2len(ptr) + 1; 1958 if (mb_ptr2char(ptr) == *initc) 1959 { 1960 if (switchit) 1961 { 1962 *findc = *initc; 1963 *initc = mb_ptr2char(prev); 1964 *backwards = FALSE; 1965 } 1966 else 1967 { 1968 *findc = mb_ptr2char(prev); 1969 *backwards = TRUE; 1970 } 1971 return; 1972 } 1973 ptr += mb_ptr2len(ptr); 1974 } 1975 else 1976 { 1977 if (*ptr == *initc) 1978 { 1979 if (switchit) 1980 { 1981 *backwards = TRUE; 1982 *findc = *initc; 1983 *initc = ptr[2]; 1984 } 1985 else 1986 { 1987 *backwards = FALSE; 1988 *findc = ptr[2]; 1989 } 1990 return; 1991 } 1992 ptr += 2; 1993 if (*ptr == *initc) 1994 { 1995 if (switchit) 1996 { 1997 *backwards = FALSE; 1998 *findc = *initc; 1999 *initc = ptr[-2]; 2000 } 2001 else 2002 { 2003 *backwards = TRUE; 2004 *findc = ptr[-2]; 2005 } 2006 return; 2007 } 2008 ++ptr; 2009 } 2010 if (*ptr == ',') 2011 ++ptr; 2012 } 2013 } 2014 2015 /* 2016 * findmatchlimit -- find the matching paren or brace, if it exists within 2017 * maxtravel lines of the cursor. A maxtravel of 0 means search until falling 2018 * off the edge of the file. 2019 * 2020 * "initc" is the character to find a match for. NUL means to find the 2021 * character at or after the cursor. Special values: 2022 * '*' look for C-style comment / * 2023 * '/' look for C-style comment / *, ignoring comment-end 2024 * '#' look for preprocessor directives 2025 * 'R' look for raw string start: R"delim(text)delim" (only backwards) 2026 * 2027 * flags: FM_BACKWARD search backwards (when initc is '/', '*' or '#') 2028 * FM_FORWARD search forwards (when initc is '/', '*' or '#') 2029 * FM_BLOCKSTOP stop at start/end of block ({ or } in column 0) 2030 * FM_SKIPCOMM skip comments (not implemented yet!) 2031 * 2032 * "oap" is only used to set oap->motion_type for a linewise motion, it can be 2033 * NULL 2034 */ 2035 2036 pos_T * 2037 findmatchlimit( 2038 oparg_T *oap, 2039 int initc, 2040 int flags, 2041 int maxtravel) 2042 { 2043 static pos_T pos; // current search position 2044 int findc = 0; // matching brace 2045 int c; 2046 int count = 0; // cumulative number of braces 2047 int backwards = FALSE; // init for gcc 2048 int raw_string = FALSE; // search for raw string 2049 int inquote = FALSE; // TRUE when inside quotes 2050 char_u *linep; // pointer to current line 2051 char_u *ptr; 2052 int do_quotes; // check for quotes in current line 2053 int at_start; // do_quotes value at start position 2054 int hash_dir = 0; // Direction searched for # things 2055 int comment_dir = 0; // Direction searched for comments 2056 pos_T match_pos; // Where last slash-star was found 2057 int start_in_quotes; // start position is in quotes 2058 int traveled = 0; // how far we've searched so far 2059 int ignore_cend = FALSE; // ignore comment end 2060 int cpo_match; // vi compatible matching 2061 int cpo_bsl; // don't recognize backslashes 2062 int match_escaped = 0; // search for escaped match 2063 int dir; // Direction to search 2064 int comment_col = MAXCOL; // start of / / comment 2065 #ifdef FEAT_LISP 2066 int lispcomm = FALSE; // inside of Lisp-style comment 2067 int lisp = curbuf->b_p_lisp; // engage Lisp-specific hacks ;) 2068 #endif 2069 2070 pos = curwin->w_cursor; 2071 pos.coladd = 0; 2072 linep = ml_get(pos.lnum); 2073 2074 cpo_match = (vim_strchr(p_cpo, CPO_MATCH) != NULL); 2075 cpo_bsl = (vim_strchr(p_cpo, CPO_MATCHBSL) != NULL); 2076 2077 // Direction to search when initc is '/', '*' or '#' 2078 if (flags & FM_BACKWARD) 2079 dir = BACKWARD; 2080 else if (flags & FM_FORWARD) 2081 dir = FORWARD; 2082 else 2083 dir = 0; 2084 2085 /* 2086 * if initc given, look in the table for the matching character 2087 * '/' and '*' are special cases: look for start or end of comment. 2088 * When '/' is used, we ignore running backwards into an star-slash, for 2089 * "[*" command, we just want to find any comment. 2090 */ 2091 if (initc == '/' || initc == '*' || initc == 'R') 2092 { 2093 comment_dir = dir; 2094 if (initc == '/') 2095 ignore_cend = TRUE; 2096 backwards = (dir == FORWARD) ? FALSE : TRUE; 2097 raw_string = (initc == 'R'); 2098 initc = NUL; 2099 } 2100 else if (initc != '#' && initc != NUL) 2101 { 2102 find_mps_values(&initc, &findc, &backwards, TRUE); 2103 if (findc == NUL) 2104 return NULL; 2105 } 2106 else 2107 { 2108 /* 2109 * Either initc is '#', or no initc was given and we need to look 2110 * under the cursor. 2111 */ 2112 if (initc == '#') 2113 { 2114 hash_dir = dir; 2115 } 2116 else 2117 { 2118 /* 2119 * initc was not given, must look for something to match under 2120 * or near the cursor. 2121 * Only check for special things when 'cpo' doesn't have '%'. 2122 */ 2123 if (!cpo_match) 2124 { 2125 // Are we before or at #if, #else etc.? 2126 ptr = skipwhite(linep); 2127 if (*ptr == '#' && pos.col <= (colnr_T)(ptr - linep)) 2128 { 2129 ptr = skipwhite(ptr + 1); 2130 if ( STRNCMP(ptr, "if", 2) == 0 2131 || STRNCMP(ptr, "endif", 5) == 0 2132 || STRNCMP(ptr, "el", 2) == 0) 2133 hash_dir = 1; 2134 } 2135 2136 // Are we on a comment? 2137 else if (linep[pos.col] == '/') 2138 { 2139 if (linep[pos.col + 1] == '*') 2140 { 2141 comment_dir = FORWARD; 2142 backwards = FALSE; 2143 pos.col++; 2144 } 2145 else if (pos.col > 0 && linep[pos.col - 1] == '*') 2146 { 2147 comment_dir = BACKWARD; 2148 backwards = TRUE; 2149 pos.col--; 2150 } 2151 } 2152 else if (linep[pos.col] == '*') 2153 { 2154 if (linep[pos.col + 1] == '/') 2155 { 2156 comment_dir = BACKWARD; 2157 backwards = TRUE; 2158 } 2159 else if (pos.col > 0 && linep[pos.col - 1] == '/') 2160 { 2161 comment_dir = FORWARD; 2162 backwards = FALSE; 2163 } 2164 } 2165 } 2166 2167 /* 2168 * If we are not on a comment or the # at the start of a line, then 2169 * look for brace anywhere on this line after the cursor. 2170 */ 2171 if (!hash_dir && !comment_dir) 2172 { 2173 /* 2174 * Find the brace under or after the cursor. 2175 * If beyond the end of the line, use the last character in 2176 * the line. 2177 */ 2178 if (linep[pos.col] == NUL && pos.col) 2179 --pos.col; 2180 for (;;) 2181 { 2182 initc = PTR2CHAR(linep + pos.col); 2183 if (initc == NUL) 2184 break; 2185 2186 find_mps_values(&initc, &findc, &backwards, FALSE); 2187 if (findc) 2188 break; 2189 pos.col += mb_ptr2len(linep + pos.col); 2190 } 2191 if (!findc) 2192 { 2193 // no brace in the line, maybe use " #if" then 2194 if (!cpo_match && *skipwhite(linep) == '#') 2195 hash_dir = 1; 2196 else 2197 return NULL; 2198 } 2199 else if (!cpo_bsl) 2200 { 2201 int col, bslcnt = 0; 2202 2203 // Set "match_escaped" if there are an odd number of 2204 // backslashes. 2205 for (col = pos.col; check_prevcol(linep, col, '\\', &col);) 2206 bslcnt++; 2207 match_escaped = (bslcnt & 1); 2208 } 2209 } 2210 } 2211 if (hash_dir) 2212 { 2213 /* 2214 * Look for matching #if, #else, #elif, or #endif 2215 */ 2216 if (oap != NULL) 2217 oap->motion_type = MLINE; // Linewise for this case only 2218 if (initc != '#') 2219 { 2220 ptr = skipwhite(skipwhite(linep) + 1); 2221 if (STRNCMP(ptr, "if", 2) == 0 || STRNCMP(ptr, "el", 2) == 0) 2222 hash_dir = 1; 2223 else if (STRNCMP(ptr, "endif", 5) == 0) 2224 hash_dir = -1; 2225 else 2226 return NULL; 2227 } 2228 pos.col = 0; 2229 while (!got_int) 2230 { 2231 if (hash_dir > 0) 2232 { 2233 if (pos.lnum == curbuf->b_ml.ml_line_count) 2234 break; 2235 } 2236 else if (pos.lnum == 1) 2237 break; 2238 pos.lnum += hash_dir; 2239 linep = ml_get(pos.lnum); 2240 line_breakcheck(); // check for CTRL-C typed 2241 ptr = skipwhite(linep); 2242 if (*ptr != '#') 2243 continue; 2244 pos.col = (colnr_T) (ptr - linep); 2245 ptr = skipwhite(ptr + 1); 2246 if (hash_dir > 0) 2247 { 2248 if (STRNCMP(ptr, "if", 2) == 0) 2249 count++; 2250 else if (STRNCMP(ptr, "el", 2) == 0) 2251 { 2252 if (count == 0) 2253 return &pos; 2254 } 2255 else if (STRNCMP(ptr, "endif", 5) == 0) 2256 { 2257 if (count == 0) 2258 return &pos; 2259 count--; 2260 } 2261 } 2262 else 2263 { 2264 if (STRNCMP(ptr, "if", 2) == 0) 2265 { 2266 if (count == 0) 2267 return &pos; 2268 count--; 2269 } 2270 else if (initc == '#' && STRNCMP(ptr, "el", 2) == 0) 2271 { 2272 if (count == 0) 2273 return &pos; 2274 } 2275 else if (STRNCMP(ptr, "endif", 5) == 0) 2276 count++; 2277 } 2278 } 2279 return NULL; 2280 } 2281 } 2282 2283 #ifdef FEAT_RIGHTLEFT 2284 // This is just guessing: when 'rightleft' is set, search for a matching 2285 // paren/brace in the other direction. 2286 if (curwin->w_p_rl && vim_strchr((char_u *)"()[]{}<>", initc) != NULL) 2287 backwards = !backwards; 2288 #endif 2289 2290 do_quotes = -1; 2291 start_in_quotes = MAYBE; 2292 CLEAR_POS(&match_pos); 2293 2294 // backward search: Check if this line contains a single-line comment 2295 if ((backwards && comment_dir) 2296 #ifdef FEAT_LISP 2297 || lisp 2298 #endif 2299 ) 2300 comment_col = check_linecomment(linep); 2301 #ifdef FEAT_LISP 2302 if (lisp && comment_col != MAXCOL && pos.col > (colnr_T)comment_col) 2303 lispcomm = TRUE; // find match inside this comment 2304 #endif 2305 while (!got_int) 2306 { 2307 /* 2308 * Go to the next position, forward or backward. We could use 2309 * inc() and dec() here, but that is much slower 2310 */ 2311 if (backwards) 2312 { 2313 #ifdef FEAT_LISP 2314 // char to match is inside of comment, don't search outside 2315 if (lispcomm && pos.col < (colnr_T)comment_col) 2316 break; 2317 #endif 2318 if (pos.col == 0) // at start of line, go to prev. one 2319 { 2320 if (pos.lnum == 1) // start of file 2321 break; 2322 --pos.lnum; 2323 2324 if (maxtravel > 0 && ++traveled > maxtravel) 2325 break; 2326 2327 linep = ml_get(pos.lnum); 2328 pos.col = (colnr_T)STRLEN(linep); // pos.col on trailing NUL 2329 do_quotes = -1; 2330 line_breakcheck(); 2331 2332 // Check if this line contains a single-line comment 2333 if (comment_dir 2334 #ifdef FEAT_LISP 2335 || lisp 2336 #endif 2337 ) 2338 comment_col = check_linecomment(linep); 2339 #ifdef FEAT_LISP 2340 // skip comment 2341 if (lisp && comment_col != MAXCOL) 2342 pos.col = comment_col; 2343 #endif 2344 } 2345 else 2346 { 2347 --pos.col; 2348 if (has_mbyte) 2349 pos.col -= (*mb_head_off)(linep, linep + pos.col); 2350 } 2351 } 2352 else // forward search 2353 { 2354 if (linep[pos.col] == NUL 2355 // at end of line, go to next one 2356 #ifdef FEAT_LISP 2357 // don't search for match in comment 2358 || (lisp && comment_col != MAXCOL 2359 && pos.col == (colnr_T)comment_col) 2360 #endif 2361 ) 2362 { 2363 if (pos.lnum == curbuf->b_ml.ml_line_count // end of file 2364 #ifdef FEAT_LISP 2365 // line is exhausted and comment with it, 2366 // don't search for match in code 2367 || lispcomm 2368 #endif 2369 ) 2370 break; 2371 ++pos.lnum; 2372 2373 if (maxtravel && traveled++ > maxtravel) 2374 break; 2375 2376 linep = ml_get(pos.lnum); 2377 pos.col = 0; 2378 do_quotes = -1; 2379 line_breakcheck(); 2380 #ifdef FEAT_LISP 2381 if (lisp) // find comment pos in new line 2382 comment_col = check_linecomment(linep); 2383 #endif 2384 } 2385 else 2386 { 2387 if (has_mbyte) 2388 pos.col += (*mb_ptr2len)(linep + pos.col); 2389 else 2390 ++pos.col; 2391 } 2392 } 2393 2394 /* 2395 * If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0. 2396 */ 2397 if (pos.col == 0 && (flags & FM_BLOCKSTOP) && 2398 (linep[0] == '{' || linep[0] == '}')) 2399 { 2400 if (linep[0] == findc && count == 0) // match! 2401 return &pos; 2402 break; // out of scope 2403 } 2404 2405 if (comment_dir) 2406 { 2407 // Note: comments do not nest, and we ignore quotes in them 2408 // TODO: ignore comment brackets inside strings 2409 if (comment_dir == FORWARD) 2410 { 2411 if (linep[pos.col] == '*' && linep[pos.col + 1] == '/') 2412 { 2413 pos.col++; 2414 return &pos; 2415 } 2416 } 2417 else // Searching backwards 2418 { 2419 /* 2420 * A comment may contain / * or / /, it may also start or end 2421 * with / * /. Ignore a / * after / / and after *. 2422 */ 2423 if (pos.col == 0) 2424 continue; 2425 else if (raw_string) 2426 { 2427 if (linep[pos.col - 1] == 'R' 2428 && linep[pos.col] == '"' 2429 && vim_strchr(linep + pos.col + 1, '(') != NULL) 2430 { 2431 // Possible start of raw string. Now that we have the 2432 // delimiter we can check if it ends before where we 2433 // started searching, or before the previously found 2434 // raw string start. 2435 if (!find_rawstring_end(linep, &pos, 2436 count > 0 ? &match_pos : &curwin->w_cursor)) 2437 { 2438 count++; 2439 match_pos = pos; 2440 match_pos.col--; 2441 } 2442 linep = ml_get(pos.lnum); // may have been released 2443 } 2444 } 2445 else if ( linep[pos.col - 1] == '/' 2446 && linep[pos.col] == '*' 2447 && (pos.col == 1 || linep[pos.col - 2] != '*') 2448 && (int)pos.col < comment_col) 2449 { 2450 count++; 2451 match_pos = pos; 2452 match_pos.col--; 2453 } 2454 else if (linep[pos.col - 1] == '*' && linep[pos.col] == '/') 2455 { 2456 if (count > 0) 2457 pos = match_pos; 2458 else if (pos.col > 1 && linep[pos.col - 2] == '/' 2459 && (int)pos.col <= comment_col) 2460 pos.col -= 2; 2461 else if (ignore_cend) 2462 continue; 2463 else 2464 return NULL; 2465 return &pos; 2466 } 2467 } 2468 continue; 2469 } 2470 2471 /* 2472 * If smart matching ('cpoptions' does not contain '%'), braces inside 2473 * of quotes are ignored, but only if there is an even number of 2474 * quotes in the line. 2475 */ 2476 if (cpo_match) 2477 do_quotes = 0; 2478 else if (do_quotes == -1) 2479 { 2480 /* 2481 * Count the number of quotes in the line, skipping \" and '"'. 2482 * Watch out for "\\". 2483 */ 2484 at_start = do_quotes; 2485 for (ptr = linep; *ptr; ++ptr) 2486 { 2487 if (ptr == linep + pos.col + backwards) 2488 at_start = (do_quotes & 1); 2489 if (*ptr == '"' 2490 && (ptr == linep || ptr[-1] != '\'' || ptr[1] != '\'')) 2491 ++do_quotes; 2492 if (*ptr == '\\' && ptr[1] != NUL) 2493 ++ptr; 2494 } 2495 do_quotes &= 1; // result is 1 with even number of quotes 2496 2497 /* 2498 * If we find an uneven count, check current line and previous 2499 * one for a '\' at the end. 2500 */ 2501 if (!do_quotes) 2502 { 2503 inquote = FALSE; 2504 if (ptr[-1] == '\\') 2505 { 2506 do_quotes = 1; 2507 if (start_in_quotes == MAYBE) 2508 { 2509 // Do we need to use at_start here? 2510 inquote = TRUE; 2511 start_in_quotes = TRUE; 2512 } 2513 else if (backwards) 2514 inquote = TRUE; 2515 } 2516 if (pos.lnum > 1) 2517 { 2518 ptr = ml_get(pos.lnum - 1); 2519 if (*ptr && *(ptr + STRLEN(ptr) - 1) == '\\') 2520 { 2521 do_quotes = 1; 2522 if (start_in_quotes == MAYBE) 2523 { 2524 inquote = at_start; 2525 if (inquote) 2526 start_in_quotes = TRUE; 2527 } 2528 else if (!backwards) 2529 inquote = TRUE; 2530 } 2531 2532 // ml_get() only keeps one line, need to get linep again 2533 linep = ml_get(pos.lnum); 2534 } 2535 } 2536 } 2537 if (start_in_quotes == MAYBE) 2538 start_in_quotes = FALSE; 2539 2540 /* 2541 * If 'smartmatch' is set: 2542 * Things inside quotes are ignored by setting 'inquote'. If we 2543 * find a quote without a preceding '\' invert 'inquote'. At the 2544 * end of a line not ending in '\' we reset 'inquote'. 2545 * 2546 * In lines with an uneven number of quotes (without preceding '\') 2547 * we do not know which part to ignore. Therefore we only set 2548 * inquote if the number of quotes in a line is even, unless this 2549 * line or the previous one ends in a '\'. Complicated, isn't it? 2550 */ 2551 c = PTR2CHAR(linep + pos.col); 2552 switch (c) 2553 { 2554 case NUL: 2555 // at end of line without trailing backslash, reset inquote 2556 if (pos.col == 0 || linep[pos.col - 1] != '\\') 2557 { 2558 inquote = FALSE; 2559 start_in_quotes = FALSE; 2560 } 2561 break; 2562 2563 case '"': 2564 // a quote that is preceded with an odd number of backslashes is 2565 // ignored 2566 if (do_quotes) 2567 { 2568 int col; 2569 2570 for (col = pos.col - 1; col >= 0; --col) 2571 if (linep[col] != '\\') 2572 break; 2573 if ((((int)pos.col - 1 - col) & 1) == 0) 2574 { 2575 inquote = !inquote; 2576 start_in_quotes = FALSE; 2577 } 2578 } 2579 break; 2580 2581 /* 2582 * If smart matching ('cpoptions' does not contain '%'): 2583 * Skip things in single quotes: 'x' or '\x'. Be careful for single 2584 * single quotes, eg jon's. Things like '\233' or '\x3f' are not 2585 * skipped, there is never a brace in them. 2586 * Ignore this when finding matches for `'. 2587 */ 2588 case '\'': 2589 if (!cpo_match && initc != '\'' && findc != '\'') 2590 { 2591 if (backwards) 2592 { 2593 if (pos.col > 1) 2594 { 2595 if (linep[pos.col - 2] == '\'') 2596 { 2597 pos.col -= 2; 2598 break; 2599 } 2600 else if (linep[pos.col - 2] == '\\' && 2601 pos.col > 2 && linep[pos.col - 3] == '\'') 2602 { 2603 pos.col -= 3; 2604 break; 2605 } 2606 } 2607 } 2608 else if (linep[pos.col + 1]) // forward search 2609 { 2610 if (linep[pos.col + 1] == '\\' && 2611 linep[pos.col + 2] && linep[pos.col + 3] == '\'') 2612 { 2613 pos.col += 3; 2614 break; 2615 } 2616 else if (linep[pos.col + 2] == '\'') 2617 { 2618 pos.col += 2; 2619 break; 2620 } 2621 } 2622 } 2623 // FALLTHROUGH 2624 2625 default: 2626 #ifdef FEAT_LISP 2627 /* 2628 * For Lisp skip over backslashed (), {} and []. 2629 * (actually, we skip #\( et al) 2630 */ 2631 if (curbuf->b_p_lisp 2632 && vim_strchr((char_u *)"(){}[]", c) != NULL 2633 && pos.col > 1 2634 && check_prevcol(linep, pos.col, '\\', NULL) 2635 && check_prevcol(linep, pos.col - 1, '#', NULL)) 2636 break; 2637 #endif 2638 2639 // Check for match outside of quotes, and inside of 2640 // quotes when the start is also inside of quotes. 2641 if ((!inquote || start_in_quotes == TRUE) 2642 && (c == initc || c == findc)) 2643 { 2644 int col, bslcnt = 0; 2645 2646 if (!cpo_bsl) 2647 { 2648 for (col = pos.col; check_prevcol(linep, col, '\\', &col);) 2649 bslcnt++; 2650 } 2651 // Only accept a match when 'M' is in 'cpo' or when escaping 2652 // is what we expect. 2653 if (cpo_bsl || (bslcnt & 1) == match_escaped) 2654 { 2655 if (c == initc) 2656 count++; 2657 else 2658 { 2659 if (count == 0) 2660 return &pos; 2661 count--; 2662 } 2663 } 2664 } 2665 } 2666 } 2667 2668 if (comment_dir == BACKWARD && count > 0) 2669 { 2670 pos = match_pos; 2671 return &pos; 2672 } 2673 return (pos_T *)NULL; // never found it 2674 } 2675 2676 /* 2677 * Check if line[] contains a / / comment. 2678 * Return MAXCOL if not, otherwise return the column. 2679 * TODO: skip strings. 2680 */ 2681 static int 2682 check_linecomment(char_u *line) 2683 { 2684 char_u *p; 2685 2686 p = line; 2687 #ifdef FEAT_LISP 2688 // skip Lispish one-line comments 2689 if (curbuf->b_p_lisp) 2690 { 2691 if (vim_strchr(p, ';') != NULL) // there may be comments 2692 { 2693 int in_str = FALSE; // inside of string 2694 2695 p = line; // scan from start 2696 while ((p = vim_strpbrk(p, (char_u *)"\";")) != NULL) 2697 { 2698 if (*p == '"') 2699 { 2700 if (in_str) 2701 { 2702 if (*(p - 1) != '\\') // skip escaped quote 2703 in_str = FALSE; 2704 } 2705 else if (p == line || ((p - line) >= 2 2706 // skip #\" form 2707 && *(p - 1) != '\\' && *(p - 2) != '#')) 2708 in_str = TRUE; 2709 } 2710 else if (!in_str && ((p - line) < 2 2711 || (*(p - 1) != '\\' && *(p - 2) != '#'))) 2712 break; // found! 2713 ++p; 2714 } 2715 } 2716 else 2717 p = NULL; 2718 } 2719 else 2720 #endif 2721 while ((p = vim_strchr(p, '/')) != NULL) 2722 { 2723 // accept a double /, unless it's preceded with * and followed by *, 2724 // because * / / * is an end and start of a C comment 2725 if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*')) 2726 break; 2727 ++p; 2728 } 2729 2730 if (p == NULL) 2731 return MAXCOL; 2732 return (int)(p - line); 2733 } 2734 2735 /* 2736 * Move cursor briefly to character matching the one under the cursor. 2737 * Used for Insert mode and "r" command. 2738 * Show the match only if it is visible on the screen. 2739 * If there isn't a match, then beep. 2740 */ 2741 void 2742 showmatch( 2743 int c) // char to show match for 2744 { 2745 pos_T *lpos, save_cursor; 2746 pos_T mpos; 2747 colnr_T vcol; 2748 long save_so; 2749 long save_siso; 2750 #ifdef CURSOR_SHAPE 2751 int save_state; 2752 #endif 2753 colnr_T save_dollar_vcol; 2754 char_u *p; 2755 long *so = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; 2756 long *siso = curwin->w_p_siso >= 0 ? &curwin->w_p_siso : &p_siso; 2757 2758 /* 2759 * Only show match for chars in the 'matchpairs' option. 2760 */ 2761 // 'matchpairs' is "x:y,x:y" 2762 for (p = curbuf->b_p_mps; *p != NUL; ++p) 2763 { 2764 #ifdef FEAT_RIGHTLEFT 2765 if (PTR2CHAR(p) == c && (curwin->w_p_rl ^ p_ri)) 2766 break; 2767 #endif 2768 p += mb_ptr2len(p) + 1; 2769 if (PTR2CHAR(p) == c 2770 #ifdef FEAT_RIGHTLEFT 2771 && !(curwin->w_p_rl ^ p_ri) 2772 #endif 2773 ) 2774 break; 2775 p += mb_ptr2len(p); 2776 if (*p == NUL) 2777 return; 2778 } 2779 2780 if ((lpos = findmatch(NULL, NUL)) == NULL) // no match, so beep 2781 vim_beep(BO_MATCH); 2782 else if (lpos->lnum >= curwin->w_topline && lpos->lnum < curwin->w_botline) 2783 { 2784 if (!curwin->w_p_wrap) 2785 getvcol(curwin, lpos, NULL, &vcol, NULL); 2786 if (curwin->w_p_wrap || (vcol >= curwin->w_leftcol 2787 && vcol < curwin->w_leftcol + curwin->w_width)) 2788 { 2789 mpos = *lpos; // save the pos, update_screen() may change it 2790 save_cursor = curwin->w_cursor; 2791 save_so = *so; 2792 save_siso = *siso; 2793 // Handle "$" in 'cpo': If the ')' is typed on top of the "$", 2794 // stop displaying the "$". 2795 if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) 2796 dollar_vcol = -1; 2797 ++curwin->w_virtcol; // do display ')' just before "$" 2798 update_screen(VALID); // show the new char first 2799 2800 save_dollar_vcol = dollar_vcol; 2801 #ifdef CURSOR_SHAPE 2802 save_state = State; 2803 State = SHOWMATCH; 2804 ui_cursor_shape(); // may show different cursor shape 2805 #endif 2806 curwin->w_cursor = mpos; // move to matching char 2807 *so = 0; // don't use 'scrolloff' here 2808 *siso = 0; // don't use 'sidescrolloff' here 2809 showruler(FALSE); 2810 setcursor(); 2811 cursor_on(); // make sure that the cursor is shown 2812 out_flush_cursor(TRUE, FALSE); 2813 2814 // Restore dollar_vcol(), because setcursor() may call curs_rows() 2815 // which resets it if the matching position is in a previous line 2816 // and has a higher column number. 2817 dollar_vcol = save_dollar_vcol; 2818 2819 /* 2820 * brief pause, unless 'm' is present in 'cpo' and a character is 2821 * available. 2822 */ 2823 if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL) 2824 ui_delay(p_mat * 100L + 8, TRUE); 2825 else if (!char_avail()) 2826 ui_delay(p_mat * 100L + 9, FALSE); 2827 curwin->w_cursor = save_cursor; // restore cursor position 2828 *so = save_so; 2829 *siso = save_siso; 2830 #ifdef CURSOR_SHAPE 2831 State = save_state; 2832 ui_cursor_shape(); // may show different cursor shape 2833 #endif 2834 } 2835 } 2836 } 2837 2838 /* 2839 * Check if the pattern is zero-width. 2840 * If move is TRUE, check from the beginning of the buffer, else from position 2841 * "cur". 2842 * "direction" is FORWARD or BACKWARD. 2843 * Returns TRUE, FALSE or -1 for failure. 2844 */ 2845 static int 2846 is_zero_width(char_u *pattern, int move, pos_T *cur, int direction) 2847 { 2848 regmmatch_T regmatch; 2849 int nmatched = 0; 2850 int result = -1; 2851 pos_T pos; 2852 int called_emsg_before = called_emsg; 2853 int flag = 0; 2854 2855 if (pattern == NULL) 2856 pattern = spats[last_idx].pat; 2857 2858 if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH, 2859 SEARCH_KEEP, ®match) == FAIL) 2860 return -1; 2861 2862 // init startcol correctly 2863 regmatch.startpos[0].col = -1; 2864 // move to match 2865 if (move) 2866 { 2867 CLEAR_POS(&pos); 2868 } 2869 else 2870 { 2871 pos = *cur; 2872 // accept a match at the cursor position 2873 flag = SEARCH_START; 2874 } 2875 2876 if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1, 2877 SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) 2878 { 2879 // Zero-width pattern should match somewhere, then we can check if 2880 // start and end are in the same position. 2881 do 2882 { 2883 regmatch.startpos[0].col++; 2884 nmatched = vim_regexec_multi(®match, curwin, curbuf, 2885 pos.lnum, regmatch.startpos[0].col, NULL, NULL); 2886 if (nmatched != 0) 2887 break; 2888 } while (direction == FORWARD ? regmatch.startpos[0].col < pos.col 2889 : regmatch.startpos[0].col > pos.col); 2890 2891 if (called_emsg == called_emsg_before) 2892 { 2893 result = (nmatched != 0 2894 && regmatch.startpos[0].lnum == regmatch.endpos[0].lnum 2895 && regmatch.startpos[0].col == regmatch.endpos[0].col); 2896 } 2897 } 2898 2899 vim_regfree(regmatch.regprog); 2900 return result; 2901 } 2902 2903 2904 /* 2905 * Find next search match under cursor, cursor at end. 2906 * Used while an operator is pending, and in Visual mode. 2907 */ 2908 int 2909 current_search( 2910 long count, 2911 int forward) // TRUE for forward, FALSE for backward 2912 { 2913 pos_T start_pos; // start position of the pattern match 2914 pos_T end_pos; // end position of the pattern match 2915 pos_T orig_pos; // position of the cursor at beginning 2916 pos_T pos; // position after the pattern 2917 int i; 2918 int dir; 2919 int result; // result of various function calls 2920 char_u old_p_ws = p_ws; 2921 int flags = 0; 2922 pos_T save_VIsual = VIsual; 2923 int zero_width; 2924 2925 // Correct cursor when 'selection' is exclusive 2926 if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor)) 2927 dec_cursor(); 2928 2929 orig_pos = pos = curwin->w_cursor; 2930 if (VIsual_active) 2931 { 2932 if (forward) 2933 incl(&pos); 2934 else 2935 decl(&pos); 2936 } 2937 2938 // Is the pattern is zero-width?, this time, don't care about the direction 2939 zero_width = is_zero_width(spats[last_idx].pat, TRUE, &curwin->w_cursor, 2940 FORWARD); 2941 if (zero_width == -1) 2942 return FAIL; // pattern not found 2943 2944 /* 2945 * The trick is to first search backwards and then search forward again, 2946 * so that a match at the current cursor position will be correctly 2947 * captured. 2948 */ 2949 for (i = 0; i < 2; i++) 2950 { 2951 if (forward) 2952 dir = i; 2953 else 2954 dir = !i; 2955 2956 flags = 0; 2957 if (!dir && !zero_width) 2958 flags = SEARCH_END; 2959 end_pos = pos; 2960 2961 // wrapping should not occur in the first round 2962 if (i == 0) 2963 p_ws = FALSE; 2964 2965 result = searchit(curwin, curbuf, &pos, &end_pos, 2966 (dir ? FORWARD : BACKWARD), 2967 spats[last_idx].pat, (long) (i ? count : 1), 2968 SEARCH_KEEP | flags, RE_SEARCH, NULL); 2969 2970 p_ws = old_p_ws; 2971 2972 // First search may fail, but then start searching from the 2973 // beginning of the file (cursor might be on the search match) 2974 // except when Visual mode is active, so that extending the visual 2975 // selection works. 2976 if (i == 1 && !result) // not found, abort 2977 { 2978 curwin->w_cursor = orig_pos; 2979 if (VIsual_active) 2980 VIsual = save_VIsual; 2981 return FAIL; 2982 } 2983 else if (i == 0 && !result) 2984 { 2985 if (forward) 2986 { 2987 // try again from start of buffer 2988 CLEAR_POS(&pos); 2989 } 2990 else 2991 { 2992 // try again from end of buffer 2993 // searching backwards, so set pos to last line and col 2994 pos.lnum = curwin->w_buffer->b_ml.ml_line_count; 2995 pos.col = (colnr_T)STRLEN( 2996 ml_get(curwin->w_buffer->b_ml.ml_line_count)); 2997 } 2998 } 2999 } 3000 3001 start_pos = pos; 3002 3003 if (!VIsual_active) 3004 VIsual = start_pos; 3005 3006 // put cursor on last character of match 3007 curwin->w_cursor = end_pos; 3008 if (LT_POS(VIsual, end_pos) && forward) 3009 dec_cursor(); 3010 else if (VIsual_active && LT_POS(curwin->w_cursor, VIsual)) 3011 curwin->w_cursor = pos; // put the cursor on the start of the match 3012 VIsual_active = TRUE; 3013 VIsual_mode = 'v'; 3014 3015 if (*p_sel == 'e') 3016 { 3017 // Correction for exclusive selection depends on the direction. 3018 if (forward && LTOREQ_POS(VIsual, curwin->w_cursor)) 3019 inc_cursor(); 3020 else if (!forward && LTOREQ_POS(curwin->w_cursor, VIsual)) 3021 inc(&VIsual); 3022 } 3023 3024 #ifdef FEAT_FOLDING 3025 if (fdo_flags & FDO_SEARCH && KeyTyped) 3026 foldOpenCursor(); 3027 #endif 3028 3029 may_start_select('c'); 3030 setmouse(); 3031 #ifdef FEAT_CLIPBOARD 3032 // Make sure the clipboard gets updated. Needed because start and 3033 // end are still the same, and the selection needs to be owned 3034 clip_star.vmode = NUL; 3035 #endif 3036 redraw_curbuf_later(INVERTED); 3037 showmode(); 3038 3039 return OK; 3040 } 3041 3042 #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(FEAT_TEXTOBJ) \ 3043 || defined(PROTO) 3044 /* 3045 * return TRUE if line 'lnum' is empty or has white chars only. 3046 */ 3047 int 3048 linewhite(linenr_T lnum) 3049 { 3050 char_u *p; 3051 3052 p = skipwhite(ml_get(lnum)); 3053 return (*p == NUL); 3054 } 3055 #endif 3056 3057 /* 3058 * Add the search count "[3/19]" to "msgbuf". 3059 * When "recompute" is TRUE always recompute the numbers. 3060 */ 3061 static void 3062 search_stat( 3063 int dirc, 3064 pos_T *pos, 3065 int show_top_bot_msg, 3066 char_u *msgbuf, 3067 int recompute) 3068 { 3069 int save_ws = p_ws; 3070 int wraparound = FALSE; 3071 pos_T p = (*pos); 3072 static pos_T lastpos = {0, 0, 0}; 3073 static int cur = 0; 3074 static int cnt = 0; 3075 static int chgtick = 0; 3076 static char_u *lastpat = NULL; 3077 static buf_T *lbuf = NULL; 3078 #ifdef FEAT_RELTIME 3079 proftime_T start; 3080 #endif 3081 #define OUT_OF_TIME 999 3082 3083 wraparound = ((dirc == '?' && LT_POS(lastpos, p)) 3084 || (dirc == '/' && LT_POS(p, lastpos))); 3085 3086 // If anything relevant changed the count has to be recomputed. 3087 // MB_STRNICMP ignores case, but we should not ignore case. 3088 // Unfortunately, there is no MB_STRNICMP function. 3089 if (!(chgtick == CHANGEDTICK(curbuf) 3090 && MB_STRNICMP(lastpat, spats[last_idx].pat, STRLEN(lastpat)) == 0 3091 && STRLEN(lastpat) == STRLEN(spats[last_idx].pat) 3092 && EQUAL_POS(lastpos, curwin->w_cursor) 3093 && lbuf == curbuf) || wraparound || cur < 0 || cur > 99 || recompute) 3094 { 3095 cur = 0; 3096 cnt = 0; 3097 CLEAR_POS(&lastpos); 3098 lbuf = curbuf; 3099 } 3100 3101 if (EQUAL_POS(lastpos, curwin->w_cursor) && !wraparound 3102 && (dirc == '/' ? cur < cnt : cur > 0)) 3103 cur += dirc == '/' ? 1 : -1; 3104 else 3105 { 3106 p_ws = FALSE; 3107 #ifdef FEAT_RELTIME 3108 profile_setlimit(20L, &start); 3109 #endif 3110 while (!got_int && searchit(curwin, curbuf, &lastpos, NULL, 3111 FORWARD, NULL, 1, SEARCH_KEEP, RE_LAST, NULL) != FAIL) 3112 { 3113 #ifdef FEAT_RELTIME 3114 // Stop after passing the time limit. 3115 if (profile_passed_limit(&start)) 3116 { 3117 cnt = OUT_OF_TIME; 3118 cur = OUT_OF_TIME; 3119 break; 3120 } 3121 #endif 3122 cnt++; 3123 if (LTOREQ_POS(lastpos, p)) 3124 cur++; 3125 fast_breakcheck(); 3126 if (cnt > 99) 3127 break; 3128 } 3129 if (got_int) 3130 cur = -1; // abort 3131 } 3132 if (cur > 0) 3133 { 3134 char t[SEARCH_STAT_BUF_LEN] = ""; 3135 size_t len; 3136 3137 #ifdef FEAT_RIGHTLEFT 3138 if (curwin->w_p_rl && *curwin->w_p_rlc == 's') 3139 { 3140 if (cur == OUT_OF_TIME) 3141 vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); 3142 else if (cnt > 99 && cur > 99) 3143 vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>99/>99]"); 3144 else if (cnt > 99) 3145 vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>99/%d]", cur); 3146 else 3147 vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", cnt, cur); 3148 } 3149 else 3150 #endif 3151 { 3152 if (cur == OUT_OF_TIME) 3153 vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); 3154 else if (cnt > 99 && cur > 99) 3155 vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>99/>99]"); 3156 else if (cnt > 99) 3157 vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>99]", cur); 3158 else 3159 vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", cur, cnt); 3160 } 3161 3162 len = STRLEN(t); 3163 if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) 3164 { 3165 mch_memmove(t + 2, t, len); 3166 t[0] = 'W'; 3167 t[1] = ' '; 3168 len += 2; 3169 } 3170 3171 mch_memmove(msgbuf + STRLEN(msgbuf) - len, t, len); 3172 if (dirc == '?' && cur == 100) 3173 cur = -1; 3174 3175 vim_free(lastpat); 3176 lastpat = vim_strsave(spats[last_idx].pat); 3177 chgtick = CHANGEDTICK(curbuf); 3178 lbuf = curbuf; 3179 lastpos = p; 3180 3181 // keep the message even after redraw, but don't put in history 3182 msg_hist_off = TRUE; 3183 give_warning(msgbuf, FALSE); 3184 msg_hist_off = FALSE; 3185 } 3186 p_ws = save_ws; 3187 } 3188 3189 #if defined(FEAT_FIND_ID) || defined(PROTO) 3190 /* 3191 * Find identifiers or defines in included files. 3192 * If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase. 3193 */ 3194 void 3195 find_pattern_in_path( 3196 char_u *ptr, // pointer to search pattern 3197 int dir UNUSED, // direction of expansion 3198 int len, // length of search pattern 3199 int whole, // match whole words only 3200 int skip_comments, // don't match inside comments 3201 int type, // Type of search; are we looking for a type? 3202 // a macro? 3203 long count, 3204 int action, // What to do when we find it 3205 linenr_T start_lnum, // first line to start searching 3206 linenr_T end_lnum) // last line for searching 3207 { 3208 SearchedFile *files; // Stack of included files 3209 SearchedFile *bigger; // When we need more space 3210 int max_path_depth = 50; 3211 long match_count = 1; 3212 3213 char_u *pat; 3214 char_u *new_fname; 3215 char_u *curr_fname = curbuf->b_fname; 3216 char_u *prev_fname = NULL; 3217 linenr_T lnum; 3218 int depth; 3219 int depth_displayed; // For type==CHECK_PATH 3220 int old_files; 3221 int already_searched; 3222 char_u *file_line; 3223 char_u *line; 3224 char_u *p; 3225 char_u save_char; 3226 int define_matched; 3227 regmatch_T regmatch; 3228 regmatch_T incl_regmatch; 3229 regmatch_T def_regmatch; 3230 int matched = FALSE; 3231 int did_show = FALSE; 3232 int found = FALSE; 3233 int i; 3234 char_u *already = NULL; 3235 char_u *startp = NULL; 3236 char_u *inc_opt = NULL; 3237 #if defined(FEAT_QUICKFIX) 3238 win_T *curwin_save = NULL; 3239 #endif 3240 3241 regmatch.regprog = NULL; 3242 incl_regmatch.regprog = NULL; 3243 def_regmatch.regprog = NULL; 3244 3245 file_line = alloc(LSIZE); 3246 if (file_line == NULL) 3247 return; 3248 3249 if (type != CHECK_PATH && type != FIND_DEFINE 3250 // when CONT_SOL is set compare "ptr" with the beginning of the line 3251 // is faster than quote_meta/regcomp/regexec "ptr" -- Acevedo 3252 && !(compl_cont_status & CONT_SOL)) 3253 { 3254 pat = alloc(len + 5); 3255 if (pat == NULL) 3256 goto fpip_end; 3257 sprintf((char *)pat, whole ? "\\<%.*s\\>" : "%.*s", len, ptr); 3258 // ignore case according to p_ic, p_scs and pat 3259 regmatch.rm_ic = ignorecase(pat); 3260 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0); 3261 vim_free(pat); 3262 if (regmatch.regprog == NULL) 3263 goto fpip_end; 3264 } 3265 inc_opt = (*curbuf->b_p_inc == NUL) ? p_inc : curbuf->b_p_inc; 3266 if (*inc_opt != NUL) 3267 { 3268 incl_regmatch.regprog = vim_regcomp(inc_opt, p_magic ? RE_MAGIC : 0); 3269 if (incl_regmatch.regprog == NULL) 3270 goto fpip_end; 3271 incl_regmatch.rm_ic = FALSE; // don't ignore case in incl. pat. 3272 } 3273 if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL)) 3274 { 3275 def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL 3276 ? p_def : curbuf->b_p_def, p_magic ? RE_MAGIC : 0); 3277 if (def_regmatch.regprog == NULL) 3278 goto fpip_end; 3279 def_regmatch.rm_ic = FALSE; // don't ignore case in define pat. 3280 } 3281 files = lalloc_clear(max_path_depth * sizeof(SearchedFile), TRUE); 3282 if (files == NULL) 3283 goto fpip_end; 3284 old_files = max_path_depth; 3285 depth = depth_displayed = -1; 3286 3287 lnum = start_lnum; 3288 if (end_lnum > curbuf->b_ml.ml_line_count) 3289 end_lnum = curbuf->b_ml.ml_line_count; 3290 if (lnum > end_lnum) // do at least one line 3291 lnum = end_lnum; 3292 line = ml_get(lnum); 3293 3294 for (;;) 3295 { 3296 if (incl_regmatch.regprog != NULL 3297 && vim_regexec(&incl_regmatch, line, (colnr_T)0)) 3298 { 3299 char_u *p_fname = (curr_fname == curbuf->b_fname) 3300 ? curbuf->b_ffname : curr_fname; 3301 3302 if (inc_opt != NULL && strstr((char *)inc_opt, "\\zs") != NULL) 3303 // Use text from '\zs' to '\ze' (or end) of 'include'. 3304 new_fname = find_file_name_in_path(incl_regmatch.startp[0], 3305 (int)(incl_regmatch.endp[0] - incl_regmatch.startp[0]), 3306 FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname); 3307 else 3308 // Use text after match with 'include'. 3309 new_fname = file_name_in_line(incl_regmatch.endp[0], 0, 3310 FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname, NULL); 3311 already_searched = FALSE; 3312 if (new_fname != NULL) 3313 { 3314 // Check whether we have already searched in this file 3315 for (i = 0;; i++) 3316 { 3317 if (i == depth + 1) 3318 i = old_files; 3319 if (i == max_path_depth) 3320 break; 3321 if (fullpathcmp(new_fname, files[i].name, TRUE, TRUE) 3322 & FPC_SAME) 3323 { 3324 if (type != CHECK_PATH && 3325 action == ACTION_SHOW_ALL && files[i].matched) 3326 { 3327 msg_putchar('\n'); // cursor below last one 3328 if (!got_int) // don't display if 'q' 3329 // typed at "--more--" 3330 // message 3331 { 3332 msg_home_replace_hl(new_fname); 3333 msg_puts(_(" (includes previously listed match)")); 3334 prev_fname = NULL; 3335 } 3336 } 3337 VIM_CLEAR(new_fname); 3338 already_searched = TRUE; 3339 break; 3340 } 3341 } 3342 } 3343 3344 if (type == CHECK_PATH && (action == ACTION_SHOW_ALL 3345 || (new_fname == NULL && !already_searched))) 3346 { 3347 if (did_show) 3348 msg_putchar('\n'); // cursor below last one 3349 else 3350 { 3351 gotocmdline(TRUE); // cursor at status line 3352 msg_puts_title(_("--- Included files ")); 3353 if (action != ACTION_SHOW_ALL) 3354 msg_puts_title(_("not found ")); 3355 msg_puts_title(_("in path ---\n")); 3356 } 3357 did_show = TRUE; 3358 while (depth_displayed < depth && !got_int) 3359 { 3360 ++depth_displayed; 3361 for (i = 0; i < depth_displayed; i++) 3362 msg_puts(" "); 3363 msg_home_replace(files[depth_displayed].name); 3364 msg_puts(" -->\n"); 3365 } 3366 if (!got_int) // don't display if 'q' typed 3367 // for "--more--" message 3368 { 3369 for (i = 0; i <= depth_displayed; i++) 3370 msg_puts(" "); 3371 if (new_fname != NULL) 3372 { 3373 // using "new_fname" is more reliable, e.g., when 3374 // 'includeexpr' is set. 3375 msg_outtrans_attr(new_fname, HL_ATTR(HLF_D)); 3376 } 3377 else 3378 { 3379 /* 3380 * Isolate the file name. 3381 * Include the surrounding "" or <> if present. 3382 */ 3383 if (inc_opt != NULL 3384 && strstr((char *)inc_opt, "\\zs") != NULL) 3385 { 3386 // pattern contains \zs, use the match 3387 p = incl_regmatch.startp[0]; 3388 i = (int)(incl_regmatch.endp[0] 3389 - incl_regmatch.startp[0]); 3390 } 3391 else 3392 { 3393 // find the file name after the end of the match 3394 for (p = incl_regmatch.endp[0]; 3395 *p && !vim_isfilec(*p); p++) 3396 ; 3397 for (i = 0; vim_isfilec(p[i]); i++) 3398 ; 3399 } 3400 3401 if (i == 0) 3402 { 3403 // Nothing found, use the rest of the line. 3404 p = incl_regmatch.endp[0]; 3405 i = (int)STRLEN(p); 3406 } 3407 // Avoid checking before the start of the line, can 3408 // happen if \zs appears in the regexp. 3409 else if (p > line) 3410 { 3411 if (p[-1] == '"' || p[-1] == '<') 3412 { 3413 --p; 3414 ++i; 3415 } 3416 if (p[i] == '"' || p[i] == '>') 3417 ++i; 3418 } 3419 save_char = p[i]; 3420 p[i] = NUL; 3421 msg_outtrans_attr(p, HL_ATTR(HLF_D)); 3422 p[i] = save_char; 3423 } 3424 3425 if (new_fname == NULL && action == ACTION_SHOW_ALL) 3426 { 3427 if (already_searched) 3428 msg_puts(_(" (Already listed)")); 3429 else 3430 msg_puts(_(" NOT FOUND")); 3431 } 3432 } 3433 out_flush(); // output each line directly 3434 } 3435 3436 if (new_fname != NULL) 3437 { 3438 // Push the new file onto the file stack 3439 if (depth + 1 == old_files) 3440 { 3441 bigger = ALLOC_MULT(SearchedFile, max_path_depth * 2); 3442 if (bigger != NULL) 3443 { 3444 for (i = 0; i <= depth; i++) 3445 bigger[i] = files[i]; 3446 for (i = depth + 1; i < old_files + max_path_depth; i++) 3447 { 3448 bigger[i].fp = NULL; 3449 bigger[i].name = NULL; 3450 bigger[i].lnum = 0; 3451 bigger[i].matched = FALSE; 3452 } 3453 for (i = old_files; i < max_path_depth; i++) 3454 bigger[i + max_path_depth] = files[i]; 3455 old_files += max_path_depth; 3456 max_path_depth *= 2; 3457 vim_free(files); 3458 files = bigger; 3459 } 3460 } 3461 if ((files[depth + 1].fp = mch_fopen((char *)new_fname, "r")) 3462 == NULL) 3463 vim_free(new_fname); 3464 else 3465 { 3466 if (++depth == old_files) 3467 { 3468 /* 3469 * lalloc() for 'bigger' must have failed above. We 3470 * will forget one of our already visited files now. 3471 */ 3472 vim_free(files[old_files].name); 3473 ++old_files; 3474 } 3475 files[depth].name = curr_fname = new_fname; 3476 files[depth].lnum = 0; 3477 files[depth].matched = FALSE; 3478 if (action == ACTION_EXPAND) 3479 { 3480 msg_hist_off = TRUE; // reset in msg_trunc_attr() 3481 vim_snprintf((char*)IObuff, IOSIZE, 3482 _("Scanning included file: %s"), 3483 (char *)new_fname); 3484 msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R)); 3485 } 3486 else if (p_verbose >= 5) 3487 { 3488 verbose_enter(); 3489 smsg(_("Searching included file %s"), 3490 (char *)new_fname); 3491 verbose_leave(); 3492 } 3493 3494 } 3495 } 3496 } 3497 else 3498 { 3499 /* 3500 * Check if the line is a define (type == FIND_DEFINE) 3501 */ 3502 p = line; 3503 search_line: 3504 define_matched = FALSE; 3505 if (def_regmatch.regprog != NULL 3506 && vim_regexec(&def_regmatch, line, (colnr_T)0)) 3507 { 3508 /* 3509 * Pattern must be first identifier after 'define', so skip 3510 * to that position before checking for match of pattern. Also 3511 * don't let it match beyond the end of this identifier. 3512 */ 3513 p = def_regmatch.endp[0]; 3514 while (*p && !vim_iswordc(*p)) 3515 p++; 3516 define_matched = TRUE; 3517 } 3518 3519 /* 3520 * Look for a match. Don't do this if we are looking for a 3521 * define and this line didn't match define_prog above. 3522 */ 3523 if (def_regmatch.regprog == NULL || define_matched) 3524 { 3525 if (define_matched || (compl_cont_status & CONT_SOL)) 3526 { 3527 // compare the first "len" chars from "ptr" 3528 startp = skipwhite(p); 3529 if (p_ic) 3530 matched = !MB_STRNICMP(startp, ptr, len); 3531 else 3532 matched = !STRNCMP(startp, ptr, len); 3533 if (matched && define_matched && whole 3534 && vim_iswordc(startp[len])) 3535 matched = FALSE; 3536 } 3537 else if (regmatch.regprog != NULL 3538 && vim_regexec(®match, line, (colnr_T)(p - line))) 3539 { 3540 matched = TRUE; 3541 startp = regmatch.startp[0]; 3542 /* 3543 * Check if the line is not a comment line (unless we are 3544 * looking for a define). A line starting with "# define" 3545 * is not considered to be a comment line. 3546 */ 3547 if (!define_matched && skip_comments) 3548 { 3549 if ((*line != '#' || 3550 STRNCMP(skipwhite(line + 1), "define", 6) != 0) 3551 && get_leader_len(line, NULL, FALSE, TRUE)) 3552 matched = FALSE; 3553 3554 /* 3555 * Also check for a "/ *" or "/ /" before the match. 3556 * Skips lines like "int backwards; / * normal index 3557 * * /" when looking for "normal". 3558 * Note: Doesn't skip "/ *" in comments. 3559 */ 3560 p = skipwhite(line); 3561 if (matched 3562 || (p[0] == '/' && p[1] == '*') || p[0] == '*') 3563 for (p = line; *p && p < startp; ++p) 3564 { 3565 if (matched 3566 && p[0] == '/' 3567 && (p[1] == '*' || p[1] == '/')) 3568 { 3569 matched = FALSE; 3570 // After "//" all text is comment 3571 if (p[1] == '/') 3572 break; 3573 ++p; 3574 } 3575 else if (!matched && p[0] == '*' && p[1] == '/') 3576 { 3577 // Can find match after "* /". 3578 matched = TRUE; 3579 ++p; 3580 } 3581 } 3582 } 3583 } 3584 } 3585 } 3586 if (matched) 3587 { 3588 if (action == ACTION_EXPAND) 3589 { 3590 int cont_s_ipos = FALSE; 3591 int add_r; 3592 char_u *aux; 3593 3594 if (depth == -1 && lnum == curwin->w_cursor.lnum) 3595 break; 3596 found = TRUE; 3597 aux = p = startp; 3598 if (compl_cont_status & CONT_ADDING) 3599 { 3600 p += compl_length; 3601 if (vim_iswordp(p)) 3602 goto exit_matched; 3603 p = find_word_start(p); 3604 } 3605 p = find_word_end(p); 3606 i = (int)(p - aux); 3607 3608 if ((compl_cont_status & CONT_ADDING) && i == compl_length) 3609 { 3610 // IOSIZE > compl_length, so the STRNCPY works 3611 STRNCPY(IObuff, aux, i); 3612 3613 // Get the next line: when "depth" < 0 from the current 3614 // buffer, otherwise from the included file. Jump to 3615 // exit_matched when past the last line. 3616 if (depth < 0) 3617 { 3618 if (lnum >= end_lnum) 3619 goto exit_matched; 3620 line = ml_get(++lnum); 3621 } 3622 else if (vim_fgets(line = file_line, 3623 LSIZE, files[depth].fp)) 3624 goto exit_matched; 3625 3626 // we read a line, set "already" to check this "line" later 3627 // if depth >= 0 we'll increase files[depth].lnum far 3628 // bellow -- Acevedo 3629 already = aux = p = skipwhite(line); 3630 p = find_word_start(p); 3631 p = find_word_end(p); 3632 if (p > aux) 3633 { 3634 if (*aux != ')' && IObuff[i-1] != TAB) 3635 { 3636 if (IObuff[i-1] != ' ') 3637 IObuff[i++] = ' '; 3638 // IObuf =~ "\(\k\|\i\).* ", thus i >= 2 3639 if (p_js 3640 && (IObuff[i-2] == '.' 3641 || (vim_strchr(p_cpo, CPO_JOINSP) == NULL 3642 && (IObuff[i-2] == '?' 3643 || IObuff[i-2] == '!')))) 3644 IObuff[i++] = ' '; 3645 } 3646 // copy as much as possible of the new word 3647 if (p - aux >= IOSIZE - i) 3648 p = aux + IOSIZE - i - 1; 3649 STRNCPY(IObuff + i, aux, p - aux); 3650 i += (int)(p - aux); 3651 cont_s_ipos = TRUE; 3652 } 3653 IObuff[i] = NUL; 3654 aux = IObuff; 3655 3656 if (i == compl_length) 3657 goto exit_matched; 3658 } 3659 3660 add_r = ins_compl_add_infercase(aux, i, p_ic, 3661 curr_fname == curbuf->b_fname ? NULL : curr_fname, 3662 dir, cont_s_ipos); 3663 if (add_r == OK) 3664 // if dir was BACKWARD then honor it just once 3665 dir = FORWARD; 3666 else if (add_r == FAIL) 3667 break; 3668 } 3669 else if (action == ACTION_SHOW_ALL) 3670 { 3671 found = TRUE; 3672 if (!did_show) 3673 gotocmdline(TRUE); // cursor at status line 3674 if (curr_fname != prev_fname) 3675 { 3676 if (did_show) 3677 msg_putchar('\n'); // cursor below last one 3678 if (!got_int) // don't display if 'q' typed 3679 // at "--more--" message 3680 msg_home_replace_hl(curr_fname); 3681 prev_fname = curr_fname; 3682 } 3683 did_show = TRUE; 3684 if (!got_int) 3685 show_pat_in_path(line, type, TRUE, action, 3686 (depth == -1) ? NULL : files[depth].fp, 3687 (depth == -1) ? &lnum : &files[depth].lnum, 3688 match_count++); 3689 3690 // Set matched flag for this file and all the ones that 3691 // include it 3692 for (i = 0; i <= depth; ++i) 3693 files[i].matched = TRUE; 3694 } 3695 else if (--count <= 0) 3696 { 3697 found = TRUE; 3698 if (depth == -1 && lnum == curwin->w_cursor.lnum 3699 #if defined(FEAT_QUICKFIX) 3700 && g_do_tagpreview == 0 3701 #endif 3702 ) 3703 emsg(_("E387: Match is on current line")); 3704 else if (action == ACTION_SHOW) 3705 { 3706 show_pat_in_path(line, type, did_show, action, 3707 (depth == -1) ? NULL : files[depth].fp, 3708 (depth == -1) ? &lnum : &files[depth].lnum, 1L); 3709 did_show = TRUE; 3710 } 3711 else 3712 { 3713 #ifdef FEAT_GUI 3714 need_mouse_correct = TRUE; 3715 #endif 3716 #if defined(FEAT_QUICKFIX) 3717 // ":psearch" uses the preview window 3718 if (g_do_tagpreview != 0) 3719 { 3720 curwin_save = curwin; 3721 prepare_tagpreview(TRUE, TRUE, FALSE); 3722 } 3723 #endif 3724 if (action == ACTION_SPLIT) 3725 { 3726 if (win_split(0, 0) == FAIL) 3727 break; 3728 RESET_BINDING(curwin); 3729 } 3730 if (depth == -1) 3731 { 3732 // match in current file 3733 #if defined(FEAT_QUICKFIX) 3734 if (g_do_tagpreview != 0) 3735 { 3736 if (!GETFILE_SUCCESS(getfile( 3737 curwin_save->w_buffer->b_fnum, NULL, 3738 NULL, TRUE, lnum, FALSE))) 3739 break; // failed to jump to file 3740 } 3741 else 3742 #endif 3743 setpcmark(); 3744 curwin->w_cursor.lnum = lnum; 3745 check_cursor(); 3746 } 3747 else 3748 { 3749 if (!GETFILE_SUCCESS(getfile( 3750 0, files[depth].name, NULL, TRUE, 3751 files[depth].lnum, FALSE))) 3752 break; // failed to jump to file 3753 // autocommands may have changed the lnum, we don't 3754 // want that here 3755 curwin->w_cursor.lnum = files[depth].lnum; 3756 } 3757 } 3758 if (action != ACTION_SHOW) 3759 { 3760 curwin->w_cursor.col = (colnr_T)(startp - line); 3761 curwin->w_set_curswant = TRUE; 3762 } 3763 3764 #if defined(FEAT_QUICKFIX) 3765 if (g_do_tagpreview != 0 3766 && curwin != curwin_save && win_valid(curwin_save)) 3767 { 3768 // Return cursor to where we were 3769 validate_cursor(); 3770 redraw_later(VALID); 3771 win_enter(curwin_save, TRUE); 3772 } 3773 # ifdef FEAT_PROP_POPUP 3774 else if (WIN_IS_POPUP(curwin)) 3775 // can't keep focus in popup window 3776 win_enter(firstwin, TRUE); 3777 # endif 3778 #endif 3779 break; 3780 } 3781 exit_matched: 3782 matched = FALSE; 3783 // look for other matches in the rest of the line if we 3784 // are not at the end of it already 3785 if (def_regmatch.regprog == NULL 3786 && action == ACTION_EXPAND 3787 && !(compl_cont_status & CONT_SOL) 3788 && *startp != NUL 3789 && *(p = startp + mb_ptr2len(startp)) != NUL) 3790 goto search_line; 3791 } 3792 line_breakcheck(); 3793 if (action == ACTION_EXPAND) 3794 ins_compl_check_keys(30, FALSE); 3795 if (got_int || ins_compl_interrupted()) 3796 break; 3797 3798 /* 3799 * Read the next line. When reading an included file and encountering 3800 * end-of-file, close the file and continue in the file that included 3801 * it. 3802 */ 3803 while (depth >= 0 && !already 3804 && vim_fgets(line = file_line, LSIZE, files[depth].fp)) 3805 { 3806 fclose(files[depth].fp); 3807 --old_files; 3808 files[old_files].name = files[depth].name; 3809 files[old_files].matched = files[depth].matched; 3810 --depth; 3811 curr_fname = (depth == -1) ? curbuf->b_fname 3812 : files[depth].name; 3813 if (depth < depth_displayed) 3814 depth_displayed = depth; 3815 } 3816 if (depth >= 0) // we could read the line 3817 { 3818 files[depth].lnum++; 3819 // Remove any CR and LF from the line. 3820 i = (int)STRLEN(line); 3821 if (i > 0 && line[i - 1] == '\n') 3822 line[--i] = NUL; 3823 if (i > 0 && line[i - 1] == '\r') 3824 line[--i] = NUL; 3825 } 3826 else if (!already) 3827 { 3828 if (++lnum > end_lnum) 3829 break; 3830 line = ml_get(lnum); 3831 } 3832 already = NULL; 3833 } 3834 // End of big for (;;) loop. 3835 3836 // Close any files that are still open. 3837 for (i = 0; i <= depth; i++) 3838 { 3839 fclose(files[i].fp); 3840 vim_free(files[i].name); 3841 } 3842 for (i = old_files; i < max_path_depth; i++) 3843 vim_free(files[i].name); 3844 vim_free(files); 3845 3846 if (type == CHECK_PATH) 3847 { 3848 if (!did_show) 3849 { 3850 if (action != ACTION_SHOW_ALL) 3851 msg(_("All included files were found")); 3852 else 3853 msg(_("No included files")); 3854 } 3855 } 3856 else if (!found && action != ACTION_EXPAND) 3857 { 3858 if (got_int || ins_compl_interrupted()) 3859 emsg(_(e_interr)); 3860 else if (type == FIND_DEFINE) 3861 emsg(_("E388: Couldn't find definition")); 3862 else 3863 emsg(_("E389: Couldn't find pattern")); 3864 } 3865 if (action == ACTION_SHOW || action == ACTION_SHOW_ALL) 3866 msg_end(); 3867 3868 fpip_end: 3869 vim_free(file_line); 3870 vim_regfree(regmatch.regprog); 3871 vim_regfree(incl_regmatch.regprog); 3872 vim_regfree(def_regmatch.regprog); 3873 } 3874 3875 static void 3876 show_pat_in_path( 3877 char_u *line, 3878 int type, 3879 int did_show, 3880 int action, 3881 FILE *fp, 3882 linenr_T *lnum, 3883 long count) 3884 { 3885 char_u *p; 3886 3887 if (did_show) 3888 msg_putchar('\n'); // cursor below last one 3889 else if (!msg_silent) 3890 gotocmdline(TRUE); // cursor at status line 3891 if (got_int) // 'q' typed at "--more--" message 3892 return; 3893 for (;;) 3894 { 3895 p = line + STRLEN(line) - 1; 3896 if (fp != NULL) 3897 { 3898 // We used fgets(), so get rid of newline at end 3899 if (p >= line && *p == '\n') 3900 --p; 3901 if (p >= line && *p == '\r') 3902 --p; 3903 *(p + 1) = NUL; 3904 } 3905 if (action == ACTION_SHOW_ALL) 3906 { 3907 sprintf((char *)IObuff, "%3ld: ", count); // show match nr 3908 msg_puts((char *)IObuff); 3909 sprintf((char *)IObuff, "%4ld", *lnum); // show line nr 3910 // Highlight line numbers 3911 msg_puts_attr((char *)IObuff, HL_ATTR(HLF_N)); 3912 msg_puts(" "); 3913 } 3914 msg_prt_line(line, FALSE); 3915 out_flush(); // show one line at a time 3916 3917 // Definition continues until line that doesn't end with '\' 3918 if (got_int || type != FIND_DEFINE || p < line || *p != '\\') 3919 break; 3920 3921 if (fp != NULL) 3922 { 3923 if (vim_fgets(line, LSIZE, fp)) // end of file 3924 break; 3925 ++*lnum; 3926 } 3927 else 3928 { 3929 if (++*lnum > curbuf->b_ml.ml_line_count) 3930 break; 3931 line = ml_get(*lnum); 3932 } 3933 msg_putchar('\n'); 3934 } 3935 } 3936 #endif 3937 3938 #ifdef FEAT_VIMINFO 3939 /* 3940 * Return the last used search pattern at "idx". 3941 */ 3942 spat_T * 3943 get_spat(int idx) 3944 { 3945 return &spats[idx]; 3946 } 3947 3948 /* 3949 * Return the last used search pattern index. 3950 */ 3951 int 3952 get_spat_last_idx(void) 3953 { 3954 return last_idx; 3955 } 3956 #endif 3957