Mercurial > vim
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(®match, win, buf, | 716 nmatched = vim_regexec_multi(®match, 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(®match, | 814 || (nmatched = vim_regexec_multi(®match, |
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(®match, | 926 || (nmatched = vim_regexec_multi(®match, |
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(®match, curwin, curbuf, | 4824 nmatched = vim_regexec_multi(®match, 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) |