comparison src/search.c @ 11521:578df034735d v8.0.0643

patch 8.0.0643: when a pattern search is slow Vim becomes unusable commit https://github.com/vim/vim/commit/fbd0b0af6800f6ff89857863d6a07ea03f09ff6c Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jun 17 18:44:21 2017 +0200 patch 8.0.0643: when a pattern search is slow Vim becomes unusable Problem: When 'hlsearch' is set and matching with the last search pattern is very slow, Vim becomes unusable. Cannot quit search by pressing CTRL-C. Solution: When the search times out set a flag and don't try again. Check for timeout and CTRL-C in NFA loop that adds states.
author Christian Brabandt <cb@256bit.org>
date Sat, 17 Jun 2017 18:45:04 +0200
parents 9473793c7bb5
children 5e36b2f825cb
comparison
equal deleted inserted replaced
11520:8b54fc8a4b2e 11521:578df034735d
591 char_u *pat, 591 char_u *pat,
592 long count, 592 long count,
593 int options, 593 int options,
594 int pat_use, /* which pattern to use when "pat" is empty */ 594 int pat_use, /* which pattern to use when "pat" is empty */
595 linenr_T stop_lnum, /* stop after this line number when != 0 */ 595 linenr_T stop_lnum, /* stop after this line number when != 0 */
596 proftime_T *tm UNUSED) /* timeout limit or NULL */ 596 proftime_T *tm UNUSED, /* timeout limit or NULL */
597 int *timed_out UNUSED) /* set when timed out or NULL */
597 { 598 {
598 int found; 599 int found;
599 linenr_T lnum; /* no init to shut up Apollo cc */ 600 linenr_T lnum; /* no init to shut up Apollo cc */
600 colnr_T col; 601 colnr_T col;
601 regmmatch_T regmatch; 602 regmmatch_T regmatch;
713 col = at_first_line && (options & SEARCH_COL) ? pos->col 714 col = at_first_line && (options & SEARCH_COL) ? pos->col
714 : (colnr_T)0; 715 : (colnr_T)0;
715 nmatched = vim_regexec_multi(&regmatch, win, buf, 716 nmatched = vim_regexec_multi(&regmatch, win, buf,
716 lnum, col, 717 lnum, col,
717 #ifdef FEAT_RELTIME 718 #ifdef FEAT_RELTIME
718 tm 719 tm, timed_out
719 #else 720 #else
720 NULL 721 NULL, NULL
721 #endif 722 #endif
722 ); 723 );
723 /* Abort searching on an error (e.g., out of stack). */ 724 /* Abort searching on an error (e.g., out of stack). */
724 if (called_emsg) 725 if (called_emsg
726 #ifdef FEAT_RELTIME
727 || (timed_out != NULL && *timed_out)
728 #endif
729 )
725 break; 730 break;
726 if (nmatched > 0) 731 if (nmatched > 0)
727 { 732 {
728 /* match may actually be in another line when using \zs */ 733 /* match may actually be in another line when using \zs */
729 matchpos = regmatch.startpos[0]; 734 matchpos = regmatch.startpos[0];
808 if (ptr[matchcol] == NUL 813 if (ptr[matchcol] == NUL
809 || (nmatched = vim_regexec_multi(&regmatch, 814 || (nmatched = vim_regexec_multi(&regmatch,
810 win, buf, lnum + matchpos.lnum, 815 win, buf, lnum + matchpos.lnum,
811 matchcol, 816 matchcol,
812 #ifdef FEAT_RELTIME 817 #ifdef FEAT_RELTIME
813 tm 818 tm, timed_out
814 #else 819 #else
815 NULL 820 NULL, NULL
816 #endif 821 #endif
817 )) == 0) 822 )) == 0)
818 { 823 {
819 match_ok = FALSE; 824 match_ok = FALSE;
820 break; 825 break;
920 if (ptr[matchcol] == NUL 925 if (ptr[matchcol] == NUL
921 || (nmatched = vim_regexec_multi(&regmatch, 926 || (nmatched = vim_regexec_multi(&regmatch,
922 win, buf, lnum + matchpos.lnum, 927 win, buf, lnum + matchpos.lnum,
923 matchcol, 928 matchcol,
924 #ifdef FEAT_RELTIME 929 #ifdef FEAT_RELTIME
925 tm 930 tm, timed_out
926 #else 931 #else
927 NULL 932 NULL, NULL
928 #endif 933 #endif
929 )) == 0) 934 )) == 0)
930 break; 935 break;
931 936
932 /* Need to get the line pointer again, a 937 /* Need to get the line pointer again, a
1017 * Stop the search if wrapscan isn't set, "stop_lnum" is 1022 * Stop the search if wrapscan isn't set, "stop_lnum" is
1018 * specified, after an interrupt, after a match and after looping 1023 * specified, after an interrupt, after a match and after looping
1019 * twice. 1024 * twice.
1020 */ 1025 */
1021 if (!p_ws || stop_lnum != 0 || got_int || called_emsg 1026 if (!p_ws || stop_lnum != 0 || got_int || called_emsg
1027 #ifdef FEAT_RELTIME
1028 || (timed_out != NULL && *timed_out)
1029 #endif
1022 #ifdef FEAT_SEARCH_EXTRA 1030 #ifdef FEAT_SEARCH_EXTRA
1023 || break_loop 1031 || break_loop
1024 #endif 1032 #endif
1025 || found || loop) 1033 || found || loop)
1026 break; 1034 break;
1027 1035
1028 /* 1036 /*
1029 * If 'wrapscan' is set we continue at the other end of the file. 1037 * If 'wrapscan' is set we continue at the other end of the file.
1030 * If 'shortmess' does not contain 's', we give a message. 1038 * If 'shortmess' does not contain 's', we give a message.
1039 if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG)) 1047 if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
1040 give_warning((char_u *)_(dir == BACKWARD 1048 give_warning((char_u *)_(dir == BACKWARD
1041 ? top_bot_msg : bot_top_msg), TRUE); 1049 ? top_bot_msg : bot_top_msg), TRUE);
1042 } 1050 }
1043 if (got_int || called_emsg 1051 if (got_int || called_emsg
1052 #ifdef FEAT_RELTIME
1053 || (timed_out != NULL && *timed_out)
1054 #endif
1044 #ifdef FEAT_SEARCH_EXTRA 1055 #ifdef FEAT_SEARCH_EXTRA
1045 || break_loop 1056 || break_loop
1046 #endif 1057 #endif
1047 ) 1058 )
1048 break; 1059 break;
1145 oparg_T *oap, /* can be NULL */ 1156 oparg_T *oap, /* can be NULL */
1146 int dirc, /* '/' or '?' */ 1157 int dirc, /* '/' or '?' */
1147 char_u *pat, 1158 char_u *pat,
1148 long count, 1159 long count,
1149 int options, 1160 int options,
1150 proftime_T *tm) /* timeout limit or NULL */ 1161 proftime_T *tm, /* timeout limit or NULL */
1162 int *timed_out) /* flag set on timeout or NULL */
1151 { 1163 {
1152 pos_T pos; /* position of the last match */ 1164 pos_T pos; /* position of the last match */
1153 char_u *searchstr; 1165 char_u *searchstr;
1154 struct soffset old_off; 1166 struct soffset old_off;
1155 int retval; /* Return value */ 1167 int retval; /* Return value */
1431 c = searchit(curwin, curbuf, &pos, dirc == '/' ? FORWARD : BACKWARD, 1443 c = searchit(curwin, curbuf, &pos, dirc == '/' ? FORWARD : BACKWARD,
1432 searchstr, count, spats[0].off.end + (options & 1444 searchstr, count, spats[0].off.end + (options &
1433 (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS 1445 (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS
1434 + SEARCH_MSG + SEARCH_START 1446 + SEARCH_MSG + SEARCH_START
1435 + ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF))), 1447 + ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF))),
1436 RE_LAST, (linenr_T)0, tm); 1448 RE_LAST, (linenr_T)0, tm, timed_out);
1437 1449
1438 if (dircp != NULL) 1450 if (dircp != NULL)
1439 *dircp = dirc; /* restore second '/' or '?' for normal_cmd() */ 1451 *dircp = dirc; /* restore second '/' or '?' for normal_cmd() */
1440 if (c == FAIL) 1452 if (c == FAIL)
1441 { 1453 {
4670 if (!dir && !one_char) 4682 if (!dir && !one_char)
4671 flags = SEARCH_END; 4683 flags = SEARCH_END;
4672 4684
4673 result = searchit(curwin, curbuf, &pos, (dir ? FORWARD : BACKWARD), 4685 result = searchit(curwin, curbuf, &pos, (dir ? FORWARD : BACKWARD),
4674 spats[last_idx].pat, (long) (i ? count : 1), 4686 spats[last_idx].pat, (long) (i ? count : 1),
4675 SEARCH_KEEP | flags, RE_SEARCH, 0, NULL); 4687 SEARCH_KEEP | flags, RE_SEARCH, 0, NULL, NULL);
4676 4688
4677 /* First search may fail, but then start searching from the 4689 /* First search may fail, but then start searching from the
4678 * beginning of the file (cursor might be on the search match) 4690 * beginning of the file (cursor might be on the search match)
4679 * except when Visual mode is active, so that extending the visual 4691 * except when Visual mode is active, so that extending the visual
4680 * selection works. */ 4692 * selection works. */
4717 4729
4718 /* move to match, except for zero-width matches, in which case, we are 4730 /* move to match, except for zero-width matches, in which case, we are
4719 * already on the next match */ 4731 * already on the next match */
4720 if (!one_char) 4732 if (!one_char)
4721 result = searchit(curwin, curbuf, &pos, (forward ? FORWARD : BACKWARD), 4733 result = searchit(curwin, curbuf, &pos, (forward ? FORWARD : BACKWARD),
4722 spats[last_idx].pat, 0L, flags | SEARCH_KEEP, RE_SEARCH, 0, NULL); 4734 spats[last_idx].pat, 0L, flags | SEARCH_KEEP, RE_SEARCH, 0,
4735 NULL, NULL);
4723 4736
4724 if (!VIsual_active) 4737 if (!VIsual_active)
4725 VIsual = start_pos; 4738 VIsual = start_pos;
4726 4739
4727 curwin->w_cursor = pos; 4740 curwin->w_cursor = pos;
4798 /* accept a match at the cursor position */ 4811 /* accept a match at the cursor position */
4799 flag = SEARCH_START; 4812 flag = SEARCH_START;
4800 } 4813 }
4801 4814
4802 if (searchit(curwin, curbuf, &pos, FORWARD, pattern, 1, 4815 if (searchit(curwin, curbuf, &pos, FORWARD, pattern, 1,
4803 SEARCH_KEEP + flag, RE_SEARCH, 0, NULL) != FAIL) 4816 SEARCH_KEEP + flag, RE_SEARCH, 0, NULL, NULL) != FAIL)
4804 { 4817 {
4805 /* Zero-width pattern should match somewhere, then we can check if 4818 /* Zero-width pattern should match somewhere, then we can check if
4806 * start and end are in the same position. */ 4819 * start and end are in the same position. */
4807 called_emsg = FALSE; 4820 called_emsg = FALSE;
4808 do 4821 do
4809 { 4822 {
4810 regmatch.startpos[0].col++; 4823 regmatch.startpos[0].col++;
4811 nmatched = vim_regexec_multi(&regmatch, curwin, curbuf, 4824 nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
4812 pos.lnum, regmatch.startpos[0].col, NULL); 4825 pos.lnum, regmatch.startpos[0].col, NULL, NULL);
4813 if (!nmatched) 4826 if (!nmatched)
4814 break; 4827 break;
4815 } while (regmatch.startpos[0].col < pos.col); 4828 } while (regmatch.startpos[0].col < pos.col);
4816 4829
4817 if (!called_emsg) 4830 if (!called_emsg)