1
0
forked from aniani/vim

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.
This commit is contained in:
Bram Moolenaar
2017-06-17 18:44:21 +02:00
parent 8cf91286ca
commit fbd0b0af68
19 changed files with 124 additions and 68 deletions

View File

@@ -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