From fbd0b0af6800f6ff89857863d6a07ea03f09ff6c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 17 Jun 2017 18:44:21 +0200 Subject: 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. --- src/regexp_nfa.c | 54 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) (limited to 'src/regexp_nfa.c') diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c index 4e111f169..5ba80f2fe 100644 --- a/src/regexp_nfa.c +++ b/src/regexp_nfa.c @@ -311,12 +311,12 @@ static int check_char_class(int class, int c); static void nfa_save_listids(nfa_regprog_T *prog, int *list); static void nfa_restore_listids(nfa_regprog_T *prog, int *list); static int nfa_re_num_cmp(long_u val, int op, long_u pos); -static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm); -static long nfa_regexec_both(char_u *line, colnr_T col, proftime_T *tm); +static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm, int *timed_out); +static long nfa_regexec_both(char_u *line, colnr_T col, proftime_T *tm, int *timed_out); static regprog_T *nfa_regcomp(char_u *expr, int re_flags); static void nfa_regfree(regprog_T *prog); static int nfa_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col, int line_lbr); -static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm); +static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm, int *timed_out); static int match_follows(nfa_state_T *startstate, int depth); static int failure_chance(nfa_state_T *state, int depth); @@ -3959,6 +3959,7 @@ pim_info(nfa_pim_T *pim) static int nfa_match; #ifdef FEAT_RELTIME static proftime_T *nfa_time_limit; +static int *nfa_timed_out; static int nfa_time_count; #endif @@ -5508,6 +5509,20 @@ find_match_text(colnr_T startcol, int regstart, char_u *match_text) return 0L; } +#ifdef FEAT_RELTIME + static int +nfa_did_time_out() +{ + if (nfa_time_limit != NULL && profile_passed_limit(nfa_time_limit)) + { + if (nfa_timed_out != NULL) + *nfa_timed_out = TRUE; + return TRUE; + } + return FALSE; +} +#endif + /* * Main matching routine. * @@ -5551,7 +5566,7 @@ nfa_regmatch( if (got_int) return FALSE; #ifdef FEAT_RELTIME - if (nfa_time_limit != NULL && profile_passed_limit(nfa_time_limit)) + if (nfa_did_time_out()) return FALSE; #endif @@ -5694,6 +5709,19 @@ nfa_regmatch( /* compute nextlist */ for (listidx = 0; listidx < thislist->n; ++listidx) { + /* If the list gets very long there probably is something wrong. + * At least allow interrupting with CTRL-C. */ + fast_breakcheck(); + if (got_int) + break; +#ifdef FEAT_RELTIME + if (nfa_time_limit != NULL && ++nfa_time_count == 20) + { + nfa_time_count = 0; + if (nfa_did_time_out()) + break; + } +#endif t = &thislist->t[listidx]; #ifdef NFA_REGEXP_DEBUG_LOG @@ -6915,7 +6943,7 @@ nextchar: if (nfa_time_limit != NULL && ++nfa_time_count == 20) { nfa_time_count = 0; - if (profile_passed_limit(nfa_time_limit)) + if (nfa_did_time_out()) break; } #endif @@ -6948,7 +6976,8 @@ theend: nfa_regtry( nfa_regprog_T *prog, colnr_T col, - proftime_T *tm UNUSED) /* timeout limit or NULL */ + proftime_T *tm UNUSED, /* timeout limit or NULL */ + int *timed_out UNUSED) /* flag set on timeout or NULL */ { int i; regsubs_T subs, m; @@ -6961,6 +6990,7 @@ nfa_regtry( reginput = regline + col; #ifdef FEAT_RELTIME nfa_time_limit = tm; + nfa_timed_out = timed_out; nfa_time_count = 0; #endif @@ -7087,7 +7117,8 @@ nfa_regtry( nfa_regexec_both( char_u *line, colnr_T startcol, /* column to start looking for match */ - proftime_T *tm) /* timeout limit or NULL */ + proftime_T *tm, /* timeout limit or NULL */ + int *timed_out) /* flag set on timeout or NULL */ { nfa_regprog_T *prog; long retval = 0L; @@ -7181,7 +7212,7 @@ nfa_regexec_both( prog->state[i].lastlist[1] = 0; } - retval = nfa_regtry(prog, col, tm); + retval = nfa_regtry(prog, col, tm, timed_out); nfa_regengine.expr = NULL; @@ -7340,7 +7371,7 @@ nfa_regexec_nl( rex.reg_icombine = FALSE; #endif rex.reg_maxcol = 0; - return nfa_regexec_both(line, col, NULL); + return nfa_regexec_both(line, col, NULL, NULL); } @@ -7376,7 +7407,8 @@ nfa_regexec_multi( buf_T *buf, /* buffer in which to search */ linenr_T lnum, /* nr of line to start looking for match */ colnr_T col, /* column to start looking for match */ - proftime_T *tm) /* timeout limit or NULL */ + proftime_T *tm, /* timeout limit or NULL */ + int *timed_out) /* flag set on timeout or NULL */ { rex.reg_match = NULL; rex.reg_mmatch = rmp; @@ -7391,7 +7423,7 @@ nfa_regexec_multi( #endif rex.reg_maxcol = rmp->rmm_maxcol; - return nfa_regexec_both(NULL, col, tm); + return nfa_regexec_both(NULL, col, tm, timed_out); } #ifdef DEBUG -- cgit v1.2.1