mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
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.
fbd0b0af68
This commit is contained in:
parent
5f84b1dc41
commit
241b905b13
@ -3907,10 +3907,11 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
compl_direction, compl_pattern);
|
compl_direction, compl_pattern);
|
||||||
} else
|
} else
|
||||||
found_new_match = searchit(NULL, ins_buf, pos,
|
found_new_match = searchit(NULL, ins_buf, pos,
|
||||||
compl_direction,
|
compl_direction,
|
||||||
compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
|
compl_pattern, 1L,
|
||||||
RE_LAST, (linenr_T)0, NULL);
|
SEARCH_KEEP + SEARCH_NFMSG,
|
||||||
--msg_silent;
|
RE_LAST, (linenr_T)0, NULL, NULL);
|
||||||
|
msg_silent--;
|
||||||
if (!compl_started || set_match_pos) {
|
if (!compl_started || set_match_pos) {
|
||||||
/* set "compl_started" even on fail */
|
/* set "compl_started" even on fail */
|
||||||
compl_started = TRUE;
|
compl_started = TRUE;
|
||||||
|
@ -13793,7 +13793,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
|
|||||||
|
|
||||||
pos = save_cursor = curwin->w_cursor;
|
pos = save_cursor = curwin->w_cursor;
|
||||||
subpatnum = searchit(curwin, curbuf, &pos, dir, (char_u *)pat, 1,
|
subpatnum = searchit(curwin, curbuf, &pos, dir, (char_u *)pat, 1,
|
||||||
options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
|
options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
|
||||||
if (subpatnum != FAIL) {
|
if (subpatnum != FAIL) {
|
||||||
if (flags & SP_SUBPAT)
|
if (flags & SP_SUBPAT)
|
||||||
retval = subpatnum;
|
retval = subpatnum;
|
||||||
@ -14295,10 +14295,11 @@ do_searchpair(
|
|||||||
pat = pat3;
|
pat = pat3;
|
||||||
for (;; ) {
|
for (;; ) {
|
||||||
n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
|
n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
|
||||||
options, RE_SEARCH, lnum_stop, &tm);
|
options, RE_SEARCH, lnum_stop, &tm, NULL);
|
||||||
if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos)))
|
if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) {
|
||||||
/* didn't find it or found the first match again: FAIL */
|
// didn't find it or found the first match again: FAIL
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (firstpos.lnum == 0)
|
if (firstpos.lnum == 0)
|
||||||
firstpos = pos;
|
firstpos = pos;
|
||||||
|
@ -3432,7 +3432,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
|
|||||||
|| lnum <= curwin->w_botline);
|
|| lnum <= curwin->w_botline);
|
||||||
lnum++) {
|
lnum++) {
|
||||||
long nmatch = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
long nmatch = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
||||||
(colnr_T)0, NULL);
|
(colnr_T)0, NULL, NULL);
|
||||||
if (nmatch) {
|
if (nmatch) {
|
||||||
colnr_T copycol;
|
colnr_T copycol;
|
||||||
colnr_T matchcol;
|
colnr_T matchcol;
|
||||||
@ -3951,8 +3951,8 @@ skip:
|
|||||||
if (lastone
|
if (lastone
|
||||||
|| nmatch_tl > 0
|
|| nmatch_tl > 0
|
||||||
|| (nmatch = vim_regexec_multi(®match, curwin,
|
|| (nmatch = vim_regexec_multi(®match, curwin,
|
||||||
curbuf, sub_firstlnum,
|
curbuf, sub_firstlnum,
|
||||||
matchcol, NULL)) == 0
|
matchcol, NULL, NULL)) == 0
|
||||||
|| regmatch.startpos[0].lnum > 0) {
|
|| regmatch.startpos[0].lnum > 0) {
|
||||||
if (new_start != NULL) {
|
if (new_start != NULL) {
|
||||||
/*
|
/*
|
||||||
@ -4016,7 +4016,7 @@ skip:
|
|||||||
}
|
}
|
||||||
if (nmatch == -1 && !lastone)
|
if (nmatch == -1 && !lastone)
|
||||||
nmatch = vim_regexec_multi(®match, curwin, curbuf,
|
nmatch = vim_regexec_multi(®match, curwin, curbuf,
|
||||||
sub_firstlnum, matchcol, NULL);
|
sub_firstlnum, matchcol, NULL, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 5. break if there isn't another match in this line
|
* 5. break if there isn't another match in this line
|
||||||
@ -4314,7 +4314,7 @@ void ex_global(exarg_T *eap)
|
|||||||
if (global_busy) {
|
if (global_busy) {
|
||||||
lnum = curwin->w_cursor.lnum;
|
lnum = curwin->w_cursor.lnum;
|
||||||
match = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
match = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
||||||
(colnr_T)0, NULL);
|
(colnr_T)0, NULL, NULL);
|
||||||
if ((type == 'g' && match) || (type == 'v' && !match)) {
|
if ((type == 'g' && match) || (type == 'v' && !match)) {
|
||||||
global_exe_one(cmd, lnum);
|
global_exe_one(cmd, lnum);
|
||||||
}
|
}
|
||||||
@ -4323,7 +4323,7 @@ void ex_global(exarg_T *eap)
|
|||||||
for (lnum = eap->line1; lnum <= eap->line2 && !got_int; lnum++) {
|
for (lnum = eap->line1; lnum <= eap->line2 && !got_int; lnum++) {
|
||||||
// a match on this line?
|
// a match on this line?
|
||||||
match = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
match = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
||||||
(colnr_T)0, NULL);
|
(colnr_T)0, NULL, NULL);
|
||||||
if ((type == 'g' && match) || (type == 'v' && !match)) {
|
if ((type == 'g' && match) || (type == 'v' && !match)) {
|
||||||
ml_setmarked(lnum);
|
ml_setmarked(lnum);
|
||||||
ndone++;
|
ndone++;
|
||||||
|
@ -3699,7 +3699,7 @@ static linenr_T get_address(exarg_T *eap,
|
|||||||
}
|
}
|
||||||
searchcmdlen = 0;
|
searchcmdlen = 0;
|
||||||
if (!do_search(NULL, c, cmd, 1L,
|
if (!do_search(NULL, c, cmd, 1L,
|
||||||
SEARCH_HIS | SEARCH_MSG, NULL)) {
|
SEARCH_HIS | SEARCH_MSG, NULL, NULL)) {
|
||||||
curwin->w_cursor = pos;
|
curwin->w_cursor = pos;
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
goto error;
|
goto error;
|
||||||
@ -3737,7 +3737,7 @@ static linenr_T get_address(exarg_T *eap,
|
|||||||
if (searchit(curwin, curbuf, &pos,
|
if (searchit(curwin, curbuf, &pos,
|
||||||
*cmd == '?' ? BACKWARD : FORWARD,
|
*cmd == '?' ? BACKWARD : FORWARD,
|
||||||
(char_u *)"", 1L, SEARCH_MSG,
|
(char_u *)"", 1L, SEARCH_MSG,
|
||||||
i, (linenr_T)0, NULL) != FAIL)
|
i, (linenr_T)0, NULL, NULL) != FAIL)
|
||||||
lnum = pos.lnum;
|
lnum = pos.lnum;
|
||||||
else {
|
else {
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
|
@ -1061,7 +1061,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
|
|||||||
s->i = searchit(curwin, curbuf, &t,
|
s->i = searchit(curwin, curbuf, &t,
|
||||||
next_match ? FORWARD : BACKWARD,
|
next_match ? FORWARD : BACKWARD,
|
||||||
pat, s->count, search_flags,
|
pat, s->count, search_flags,
|
||||||
RE_SEARCH, 0, NULL);
|
RE_SEARCH, 0, NULL, NULL);
|
||||||
emsg_off--;
|
emsg_off--;
|
||||||
ui_busy_stop();
|
ui_busy_stop();
|
||||||
if (s->i) {
|
if (s->i) {
|
||||||
@ -1847,7 +1847,7 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
}
|
}
|
||||||
s->i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count,
|
s->i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count,
|
||||||
search_flags,
|
search_flags,
|
||||||
&tm);
|
&tm, NULL);
|
||||||
emsg_off--;
|
emsg_off--;
|
||||||
// if interrupted while searching, behave like it failed
|
// if interrupted while searching, behave like it failed
|
||||||
if (got_int) {
|
if (got_int) {
|
||||||
|
@ -3782,9 +3782,10 @@ find_decl (
|
|||||||
valid = false;
|
valid = false;
|
||||||
(void)valid; // Avoid "dead assignment" warning.
|
(void)valid; // Avoid "dead assignment" warning.
|
||||||
t = searchit(curwin, curbuf, &curwin->w_cursor, FORWARD,
|
t = searchit(curwin, curbuf, &curwin->w_cursor, FORWARD,
|
||||||
pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL);
|
pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL, NULL);
|
||||||
if (curwin->w_cursor.lnum >= old_pos.lnum)
|
if (curwin->w_cursor.lnum >= old_pos.lnum) {
|
||||||
t = false; /* match after start is failure too */
|
t = false; // match after start is failure too
|
||||||
|
}
|
||||||
|
|
||||||
if (thisblock && t != false) {
|
if (thisblock && t != false) {
|
||||||
const int64_t maxtravel = old_pos.lnum - curwin->w_cursor.lnum + 1;
|
const int64_t maxtravel = old_pos.lnum - curwin->w_cursor.lnum + 1;
|
||||||
@ -5384,7 +5385,7 @@ static int normal_search(
|
|||||||
curwin->w_set_curswant = true;
|
curwin->w_set_curswant = true;
|
||||||
|
|
||||||
i = do_search(cap->oap, dir, pat, cap->count1,
|
i = do_search(cap->oap, dir, pat, cap->count1,
|
||||||
opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, NULL);
|
opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, NULL, NULL);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
clearop(cap->oap);
|
clearop(cap->oap);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2128,8 +2128,9 @@ win_found:
|
|||||||
save_cursor = curwin->w_cursor;
|
save_cursor = curwin->w_cursor;
|
||||||
curwin->w_cursor.lnum = 0;
|
curwin->w_cursor.lnum = 0;
|
||||||
if (!do_search(NULL, '/', qf_ptr->qf_pattern, (long)1,
|
if (!do_search(NULL, '/', qf_ptr->qf_pattern, (long)1,
|
||||||
SEARCH_KEEP, NULL))
|
SEARCH_KEEP, NULL, NULL)) {
|
||||||
curwin->w_cursor = save_cursor;
|
curwin->w_cursor = save_cursor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped)
|
if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped)
|
||||||
@ -3758,7 +3759,7 @@ void ex_vimgrep(exarg_T *eap)
|
|||||||
++lnum) {
|
++lnum) {
|
||||||
col = 0;
|
col = 0;
|
||||||
while (vim_regexec_multi(®match, curwin, buf, lnum,
|
while (vim_regexec_multi(®match, curwin, buf, lnum,
|
||||||
col, NULL) > 0) {
|
col, NULL, NULL) > 0) {
|
||||||
// Pass the buffer number so that it gets used even for a
|
// Pass the buffer number so that it gets used even for a
|
||||||
// dummy buffer, unless duplicate_name is set, then the
|
// dummy buffer, unless duplicate_name is set, then the
|
||||||
// buffer will be wiped out below.
|
// buffer will be wiped out below.
|
||||||
|
@ -3297,7 +3297,7 @@ bt_regexec_nl (
|
|||||||
rex.reg_icombine = false;
|
rex.reg_icombine = false;
|
||||||
rex.reg_maxcol = 0;
|
rex.reg_maxcol = 0;
|
||||||
|
|
||||||
long r = bt_regexec_both(line, col, NULL);
|
long r = bt_regexec_both(line, col, NULL, NULL);
|
||||||
assert(r <= INT_MAX);
|
assert(r <= INT_MAX);
|
||||||
return (int)r;
|
return (int)r;
|
||||||
}
|
}
|
||||||
@ -3357,7 +3357,8 @@ static inline char_u *cstrchr(const char_u *const s, const int c)
|
|||||||
/// @return zero if there is no match and number of lines contained in the match
|
/// @return zero if there is no match and number of lines contained in the match
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
static long bt_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
|
static long bt_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
|
||||||
linenr_T lnum, colnr_T col, proftime_T *tm)
|
linenr_T lnum, colnr_T col,
|
||||||
|
proftime_T *tm, int *timed_out)
|
||||||
{
|
{
|
||||||
rex.reg_match = NULL;
|
rex.reg_match = NULL;
|
||||||
rex.reg_mmatch = rmp;
|
rex.reg_mmatch = rmp;
|
||||||
@ -3370,7 +3371,7 @@ static long bt_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
|
|||||||
rex.reg_icombine = false;
|
rex.reg_icombine = false;
|
||||||
rex.reg_maxcol = rmp->rmm_maxcol;
|
rex.reg_maxcol = rmp->rmm_maxcol;
|
||||||
|
|
||||||
return bt_regexec_both(NULL, col, tm);
|
return bt_regexec_both(NULL, col, tm, timed_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3379,8 +3380,10 @@ static long bt_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
|
|||||||
* Returns 0 for failure, number of lines contained in the match otherwise.
|
* Returns 0 for failure, number of lines contained in the match otherwise.
|
||||||
*/
|
*/
|
||||||
static long bt_regexec_both(char_u *line,
|
static long bt_regexec_both(char_u *line,
|
||||||
colnr_T col, /* column to start looking for match */
|
// column to start looking for match
|
||||||
proftime_T *tm /* timeout limit or NULL */
|
colnr_T col,
|
||||||
|
proftime_T *tm, // timeout limit or NULL
|
||||||
|
int *timed_out // flag set on timeout or NULL
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
bt_regprog_T *prog;
|
bt_regprog_T *prog;
|
||||||
@ -3525,8 +3528,12 @@ static long bt_regexec_both(char_u *line,
|
|||||||
/* Check for timeout once in a twenty times to avoid overhead. */
|
/* Check for timeout once in a twenty times to avoid overhead. */
|
||||||
if (tm != NULL && ++tm_count == 20) {
|
if (tm != NULL && ++tm_count == 20) {
|
||||||
tm_count = 0;
|
tm_count = 0;
|
||||||
if (profile_passed_limit(*tm))
|
if (profile_passed_limit(*tm)) {
|
||||||
|
if (timed_out != NULL) {
|
||||||
|
*timed_out = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7275,12 +7282,13 @@ int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col)
|
|||||||
/// Return zero if there is no match. Return number of lines contained in the
|
/// Return zero if there is no match. Return number of lines contained in the
|
||||||
/// match otherwise.
|
/// match otherwise.
|
||||||
long vim_regexec_multi(
|
long vim_regexec_multi(
|
||||||
regmmatch_T *rmp,
|
regmmatch_T *rmp,
|
||||||
win_T *win, /* window in which to search or NULL */
|
win_T *win, // window in which to search or NULL
|
||||||
buf_T *buf, /* buffer in which to search */
|
buf_T *buf, // buffer in which to search
|
||||||
linenr_T lnum, /* nr of line to start looking for match */
|
linenr_T lnum, // nr of line to start looking for match
|
||||||
colnr_T col, /* column 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 is set when timeout limit reached
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
regexec_T rex_save;
|
regexec_T rex_save;
|
||||||
@ -7293,7 +7301,7 @@ long vim_regexec_multi(
|
|||||||
rex_in_use = true;
|
rex_in_use = true;
|
||||||
|
|
||||||
int result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col,
|
int result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col,
|
||||||
tm);
|
tm, timed_out);
|
||||||
|
|
||||||
// NFA engine aborted because it's very slow, use backtracking engine instead.
|
// NFA engine aborted because it's very slow, use backtracking engine instead.
|
||||||
if (rmp->regprog->re_engine == AUTOMATIC_ENGINE
|
if (rmp->regprog->re_engine == AUTOMATIC_ENGINE
|
||||||
@ -7313,7 +7321,7 @@ long vim_regexec_multi(
|
|||||||
|
|
||||||
if (rmp->regprog != NULL) {
|
if (rmp->regprog != NULL) {
|
||||||
result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col,
|
result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col,
|
||||||
tm);
|
tm, timed_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
xfree(pat);
|
xfree(pat);
|
||||||
|
@ -156,11 +156,11 @@ struct reg_extmatch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct regengine {
|
struct regengine {
|
||||||
regprog_T *(*regcomp)(char_u*, int);
|
regprog_T *(*regcomp)(char_u *, int);
|
||||||
void (*regfree)(regprog_T *);
|
void (*regfree)(regprog_T *);
|
||||||
int (*regexec_nl)(regmatch_T*, char_u*, colnr_T, bool);
|
int (*regexec_nl)(regmatch_T *, char_u *, colnr_T, bool);
|
||||||
long (*regexec_multi)(regmmatch_T*, win_T*, buf_T*, linenr_T, colnr_T,
|
long (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, colnr_T,
|
||||||
proftime_T*);
|
proftime_T *, int *);
|
||||||
char_u *expr;
|
char_u *expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3568,6 +3568,7 @@ static char *pim_info(nfa_pim_T *pim)
|
|||||||
// Used during execution: whether a match has been found.
|
// Used during execution: whether a match has been found.
|
||||||
static int nfa_match;
|
static int nfa_match;
|
||||||
static proftime_T *nfa_time_limit;
|
static proftime_T *nfa_time_limit;
|
||||||
|
static int *nfa_timed_out;
|
||||||
static int nfa_time_count;
|
static int nfa_time_count;
|
||||||
|
|
||||||
// Copy postponed invisible match info from "from" to "to".
|
// Copy postponed invisible match info from "from" to "to".
|
||||||
@ -4939,6 +4940,17 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
|
|||||||
#undef PTR2LEN
|
#undef PTR2LEN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nfa_did_time_out(void)
|
||||||
|
{
|
||||||
|
if (nfa_time_limit != NULL && profile_passed_limit(*nfa_time_limit)) {
|
||||||
|
if (nfa_timed_out != NULL) {
|
||||||
|
*nfa_timed_out = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Main matching routine.
|
/// Main matching routine.
|
||||||
///
|
///
|
||||||
/// Run NFA to determine whether it matches reginput.
|
/// Run NFA to determine whether it matches reginput.
|
||||||
@ -4982,7 +4994,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
|
|||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (nfa_time_limit != NULL && profile_passed_limit(*nfa_time_limit)) {
|
if (nfa_did_time_out()) {
|
||||||
#ifdef NFA_REGEXP_DEBUG_LOG
|
#ifdef NFA_REGEXP_DEBUG_LOG
|
||||||
fclose(debug);
|
fclose(debug);
|
||||||
#endif
|
#endif
|
||||||
@ -5095,8 +5107,20 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
|
|||||||
if (thislist->n == 0)
|
if (thislist->n == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* compute nextlist */
|
// compute nextlist
|
||||||
for (listidx = 0; listidx < thislist->n; ++listidx) {
|
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;
|
||||||
|
}
|
||||||
|
if (nfa_time_limit != NULL && ++nfa_time_count == 20) {
|
||||||
|
nfa_time_count = 0;
|
||||||
|
if (nfa_did_time_out()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
t = &thislist->t[listidx];
|
t = &thislist->t[listidx];
|
||||||
|
|
||||||
#ifdef NFA_REGEXP_DEBUG_LOG
|
#ifdef NFA_REGEXP_DEBUG_LOG
|
||||||
@ -6218,7 +6242,7 @@ nextchar:
|
|||||||
// Check for timeout once every twenty times to avoid overhead.
|
// Check for timeout once every twenty times to avoid overhead.
|
||||||
if (nfa_time_limit != NULL && ++nfa_time_count == 20) {
|
if (nfa_time_limit != NULL && ++nfa_time_count == 20) {
|
||||||
nfa_time_count = 0;
|
nfa_time_count = 0;
|
||||||
if (profile_passed_limit(*nfa_time_limit)) {
|
if (nfa_did_time_out()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6245,7 +6269,8 @@ theend:
|
|||||||
|
|
||||||
// Try match of "prog" with at regline["col"].
|
// Try match of "prog" with at regline["col"].
|
||||||
// Returns <= 0 for failure, number of lines contained in the match otherwise.
|
// Returns <= 0 for failure, number of lines contained in the match otherwise.
|
||||||
static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm)
|
static long nfa_regtry(nfa_regprog_T *prog, colnr_T col,
|
||||||
|
proftime_T *tm, int *timed_out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
regsubs_T subs, m;
|
regsubs_T subs, m;
|
||||||
@ -6256,6 +6281,7 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm)
|
|||||||
|
|
||||||
reginput = regline + col;
|
reginput = regline + col;
|
||||||
nfa_time_limit = tm;
|
nfa_time_limit = tm;
|
||||||
|
nfa_timed_out = timed_out;
|
||||||
nfa_time_count = 0;
|
nfa_time_count = 0;
|
||||||
|
|
||||||
#ifdef REGEXP_DEBUG
|
#ifdef REGEXP_DEBUG
|
||||||
@ -6367,7 +6393,8 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm)
|
|||||||
///
|
///
|
||||||
/// @return <= 0 if there is no match and number of lines contained in the
|
/// @return <= 0 if there is no match and number of lines contained in the
|
||||||
/// match otherwise.
|
/// match otherwise.
|
||||||
static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm)
|
static long nfa_regexec_both(char_u *line, colnr_T startcol,
|
||||||
|
proftime_T *tm, int *timed_out)
|
||||||
{
|
{
|
||||||
nfa_regprog_T *prog;
|
nfa_regprog_T *prog;
|
||||||
long retval = 0L;
|
long retval = 0L;
|
||||||
@ -6449,7 +6476,7 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm)
|
|||||||
prog->state[i].lastlist[1] = 0;
|
prog->state[i].lastlist[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = nfa_regtry(prog, col, tm);
|
retval = nfa_regtry(prog, col, tm, timed_out);
|
||||||
|
|
||||||
nfa_regengine.expr = NULL;
|
nfa_regengine.expr = NULL;
|
||||||
|
|
||||||
@ -6596,7 +6623,7 @@ nfa_regexec_nl (
|
|||||||
rex.reg_ic = rmp->rm_ic;
|
rex.reg_ic = rmp->rm_ic;
|
||||||
rex.reg_icombine = false;
|
rex.reg_icombine = false;
|
||||||
rex.reg_maxcol = 0;
|
rex.reg_maxcol = 0;
|
||||||
return nfa_regexec_both(line, col, NULL);
|
return nfa_regexec_both(line, col, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches a regexp against multiple lines.
|
/// Matches a regexp against multiple lines.
|
||||||
@ -6634,7 +6661,8 @@ nfa_regexec_nl (
|
|||||||
/// @par
|
/// @par
|
||||||
/// FIXME if this behavior is not compatible.
|
/// FIXME if this behavior is not compatible.
|
||||||
static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
|
static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
|
||||||
linenr_T lnum, colnr_T col, proftime_T *tm)
|
linenr_T lnum, colnr_T col,
|
||||||
|
proftime_T *tm, int *timed_out)
|
||||||
{
|
{
|
||||||
rex.reg_match = NULL;
|
rex.reg_match = NULL;
|
||||||
rex.reg_mmatch = rmp;
|
rex.reg_mmatch = rmp;
|
||||||
@ -6647,5 +6675,5 @@ static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
|
|||||||
rex.reg_icombine = false;
|
rex.reg_icombine = false;
|
||||||
rex.reg_maxcol = rmp->rmm_maxcol;
|
rex.reg_maxcol = rmp->rmm_maxcol;
|
||||||
|
|
||||||
return nfa_regexec_both(NULL, col, tm);
|
return nfa_regexec_both(NULL, col, tm, timed_out);
|
||||||
}
|
}
|
||||||
|
@ -5651,13 +5651,15 @@ next_search_hl (
|
|||||||
&& cur != NULL
|
&& cur != NULL
|
||||||
&& shl == &cur->hl
|
&& shl == &cur->hl
|
||||||
&& cur->match.regprog == cur->hl.rm.regprog);
|
&& cur->match.regprog == cur->hl.rm.regprog);
|
||||||
|
int timed_out = false;
|
||||||
|
|
||||||
nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol, &(shl->tm));
|
nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol,
|
||||||
/* Copy the regprog, in case it got freed and recompiled. */
|
&(shl->tm), &timed_out);
|
||||||
|
// Copy the regprog, in case it got freed and recompiled.
|
||||||
if (regprog_is_copy) {
|
if (regprog_is_copy) {
|
||||||
cur->match.regprog = cur->hl.rm.regprog;
|
cur->match.regprog = cur->hl.rm.regprog;
|
||||||
}
|
}
|
||||||
if (called_emsg || got_int) {
|
if (called_emsg || got_int || timed_out) {
|
||||||
// Error while handling regexp: stop using this regexp.
|
// Error while handling regexp: stop using this regexp.
|
||||||
if (shl == &search_hl) {
|
if (shl == &search_hl) {
|
||||||
// don't free regprog in the match list, it's a copy
|
// don't free regprog in the match list, it's a copy
|
||||||
|
@ -523,9 +523,10 @@ int searchit(
|
|||||||
char_u *pat,
|
char_u *pat,
|
||||||
long count,
|
long count,
|
||||||
int options,
|
int options,
|
||||||
int pat_use, /* which pattern to use when "pat" is empty */
|
int pat_use, // which pattern to use when "pat" is empty
|
||||||
linenr_T stop_lnum, /* stop after this line number when != 0 */
|
linenr_T stop_lnum, // stop after this line number when != 0
|
||||||
proftime_T *tm /* timeout limit or NULL */
|
proftime_T *tm, // timeout limit or NULL
|
||||||
|
int *timed_out // set when timed out or NULL
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int found;
|
int found;
|
||||||
@ -620,9 +621,9 @@ int searchit(
|
|||||||
// Look for a match somewhere in line "lnum".
|
// Look for a match somewhere in line "lnum".
|
||||||
colnr_T col = at_first_line && (options & SEARCH_COL) ? pos->col : 0;
|
colnr_T col = at_first_line && (options & SEARCH_COL) ? pos->col : 0;
|
||||||
nmatched = vim_regexec_multi(®match, win, buf,
|
nmatched = vim_regexec_multi(®match, win, buf,
|
||||||
lnum, col, tm);
|
lnum, col, tm, timed_out);
|
||||||
// Abort searching on an error (e.g., out of stack).
|
// Abort searching on an error (e.g., out of stack).
|
||||||
if (called_emsg) {
|
if (called_emsg || (timed_out != NULL && *timed_out)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nmatched > 0) {
|
if (nmatched > 0) {
|
||||||
@ -686,8 +687,9 @@ int searchit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ptr[matchcol] == NUL
|
if (ptr[matchcol] == NUL
|
||||||
|| (nmatched = vim_regexec_multi(®match, win, buf, lnum,
|
|| (nmatched = vim_regexec_multi(®match, win, buf,
|
||||||
matchcol, tm)) == 0) {
|
lnum, matchcol, tm,
|
||||||
|
timed_out)) == 0) {
|
||||||
match_ok = false;
|
match_ok = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -771,7 +773,7 @@ int searchit(
|
|||||||
if (ptr[matchcol] == NUL
|
if (ptr[matchcol] == NUL
|
||||||
|| (nmatched = vim_regexec_multi(
|
|| (nmatched = vim_regexec_multi(
|
||||||
®match, win, buf, lnum + matchpos.lnum, matchcol,
|
®match, win, buf, lnum + matchpos.lnum, matchcol,
|
||||||
tm)) == 0) {
|
tm, timed_out)) == 0) {
|
||||||
// If the search timed out, we did find a match
|
// If the search timed out, we did find a match
|
||||||
// but it might be the wrong one, so that's not
|
// but it might be the wrong one, so that's not
|
||||||
// OK.
|
// OK.
|
||||||
@ -855,30 +857,35 @@ int searchit(
|
|||||||
* twice.
|
* twice.
|
||||||
*/
|
*/
|
||||||
if (!p_ws || stop_lnum != 0 || got_int || called_emsg
|
if (!p_ws || stop_lnum != 0 || got_int || called_emsg
|
||||||
|
|| (timed_out != NULL && timed_out)
|
||||||
|| break_loop
|
|| break_loop
|
||||||
|| found || loop)
|
|| found || loop) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
/*
|
//
|
||||||
* If 'wrapscan' is set we continue at the other end of the file.
|
// If 'wrapscan' is set we continue at the other end of the file.
|
||||||
* If 'shortmess' does not contain 's', we give a message.
|
// If 'shortmess' does not contain 's', we give a message.
|
||||||
* This message is also remembered in keep_msg for when the screen
|
// This message is also remembered in keep_msg for when the screen
|
||||||
* is redrawn. The keep_msg is cleared whenever another message is
|
// is redrawn. The keep_msg is cleared whenever another message is
|
||||||
* written.
|
// written.
|
||||||
*/
|
//
|
||||||
if (dir == BACKWARD) /* start second loop at the other end */
|
if (dir == BACKWARD) { // start second loop at the other end
|
||||||
lnum = buf->b_ml.ml_line_count;
|
lnum = buf->b_ml.ml_line_count;
|
||||||
else
|
} else {
|
||||||
lnum = 1;
|
lnum = 1;
|
||||||
if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
|
}
|
||||||
|
if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG)) {
|
||||||
give_warning((char_u *)_(dir == BACKWARD
|
give_warning((char_u *)_(dir == BACKWARD
|
||||||
? top_bot_msg : bot_top_msg), true);
|
? top_bot_msg : bot_top_msg), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (got_int || called_emsg
|
if (got_int || called_emsg
|
||||||
|
|| (timed_out != NULL && *timed_out)
|
||||||
|| break_loop
|
|| break_loop
|
||||||
)
|
) {
|
||||||
break;
|
break;
|
||||||
} while (--count > 0 && found); /* stop after count matches or no match */
|
}
|
||||||
|
} while (--count > 0 && found); // stop after count matches or no match
|
||||||
|
|
||||||
vim_regfree(regmatch.regprog);
|
vim_regfree(regmatch.regprog);
|
||||||
|
|
||||||
@ -965,7 +972,8 @@ int do_search(
|
|||||||
char_u *pat,
|
char_u *pat,
|
||||||
long count,
|
long count,
|
||||||
int options,
|
int options,
|
||||||
proftime_T *tm /* timeout limit or NULL */
|
proftime_T *tm, // timeout limit or NULL
|
||||||
|
int *timed_out // flag set on timeout or NULL
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
pos_T pos; /* position of the last match */
|
pos_T pos; /* position of the last match */
|
||||||
@ -1195,7 +1203,7 @@ int do_search(
|
|||||||
& (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS + SEARCH_MSG
|
& (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS + SEARCH_MSG
|
||||||
+ SEARCH_START
|
+ SEARCH_START
|
||||||
+ ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF)))),
|
+ ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF)))),
|
||||||
RE_LAST, (linenr_T)0, tm);
|
RE_LAST, (linenr_T)0, tm, timed_out);
|
||||||
|
|
||||||
if (dircp != NULL)
|
if (dircp != NULL)
|
||||||
*dircp = dirc; /* restore second '/' or '?' for normal_cmd() */
|
*dircp = dirc; /* restore second '/' or '?' for normal_cmd() */
|
||||||
@ -3978,7 +3986,7 @@ current_search(
|
|||||||
|
|
||||||
result = searchit(curwin, curbuf, &pos, (dir ? FORWARD : BACKWARD),
|
result = searchit(curwin, curbuf, &pos, (dir ? FORWARD : BACKWARD),
|
||||||
spats[last_idx].pat, i ? count : 1,
|
spats[last_idx].pat, i ? count : 1,
|
||||||
SEARCH_KEEP | flags, RE_SEARCH, 0, NULL);
|
SEARCH_KEEP | flags, RE_SEARCH, 0, NULL, NULL);
|
||||||
|
|
||||||
/* First search may fail, but then start searching from the
|
/* First search may fail, but then start searching from the
|
||||||
* beginning of the file (cursor might be on the search match)
|
* beginning of the file (cursor might be on the search match)
|
||||||
@ -4025,7 +4033,7 @@ current_search(
|
|||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
result = searchit(curwin, curbuf, &pos, direction,
|
result = searchit(curwin, curbuf, &pos, direction,
|
||||||
spats[last_idx].pat, 0L, flags | SEARCH_KEEP, RE_SEARCH,
|
spats[last_idx].pat, 0L, flags | SEARCH_KEEP, RE_SEARCH,
|
||||||
0, NULL);
|
0, NULL, NULL);
|
||||||
// Search successfull, break out from the loop
|
// Search successfull, break out from the loop
|
||||||
if (result) {
|
if (result) {
|
||||||
break;
|
break;
|
||||||
@ -4104,14 +4112,15 @@ static int is_one_char(char_u *pattern, bool move, pos_T *cur,
|
|||||||
flag = SEARCH_START;
|
flag = SEARCH_START;
|
||||||
}
|
}
|
||||||
if (searchit(curwin, curbuf, &pos, direction, pattern, 1,
|
if (searchit(curwin, curbuf, &pos, direction, pattern, 1,
|
||||||
SEARCH_KEEP + flag, RE_SEARCH, 0, NULL) != FAIL) {
|
SEARCH_KEEP + flag, RE_SEARCH, 0, NULL, NULL) != FAIL) {
|
||||||
// Zero-width pattern should match somewhere, then we can check if
|
// Zero-width pattern should match somewhere, then we can check if
|
||||||
// start and end are in the same position.
|
// start and end are in the same position.
|
||||||
called_emsg = false;
|
called_emsg = false;
|
||||||
do {
|
do {
|
||||||
regmatch.startpos[0].col++;
|
regmatch.startpos[0].col++;
|
||||||
nmatched = vim_regexec_multi(®match, curwin, curbuf,
|
nmatched = vim_regexec_multi(®match, curwin, curbuf,
|
||||||
pos.lnum, regmatch.startpos[0].col, NULL);
|
pos.lnum, regmatch.startpos[0].col,
|
||||||
|
NULL, NULL);
|
||||||
if (!nmatched) {
|
if (!nmatched) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3048,9 +3048,10 @@ void ex_spellrepall(exarg_T *eap)
|
|||||||
sub_nlines = 0;
|
sub_nlines = 0;
|
||||||
curwin->w_cursor.lnum = 0;
|
curwin->w_cursor.lnum = 0;
|
||||||
while (!got_int) {
|
while (!got_int) {
|
||||||
if (do_search(NULL, '/', frompat, 1L, SEARCH_KEEP, NULL) == 0
|
if (do_search(NULL, '/', frompat, 1L, SEARCH_KEEP, NULL, NULL) == 0
|
||||||
|| u_save_cursor() == FAIL)
|
|| u_save_cursor() == FAIL) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Only replace when the right word isn't there yet. This happens
|
// Only replace when the right word isn't there yet. This happens
|
||||||
// when changing "etc" to "etc.".
|
// when changing "etc" to "etc.".
|
||||||
|
@ -2902,7 +2902,7 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
|
|||||||
}
|
}
|
||||||
|
|
||||||
rmp->rmm_maxcol = syn_buf->b_p_smc;
|
rmp->rmm_maxcol = syn_buf->b_p_smc;
|
||||||
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, NULL);
|
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, NULL, NULL);
|
||||||
|
|
||||||
if (l_syn_time_on) {
|
if (l_syn_time_on) {
|
||||||
pt = profile_end(pt);
|
pt = profile_end(pt);
|
||||||
|
@ -2508,9 +2508,9 @@ static int jumpto_tag(
|
|||||||
save_lnum = curwin->w_cursor.lnum;
|
save_lnum = curwin->w_cursor.lnum;
|
||||||
curwin->w_cursor.lnum = 0; /* start search before first line */
|
curwin->w_cursor.lnum = 0; /* start search before first line */
|
||||||
if (do_search(NULL, pbuf[0], pbuf + 1, (long)1,
|
if (do_search(NULL, pbuf[0], pbuf + 1, (long)1,
|
||||||
search_options, NULL))
|
search_options, NULL, NULL)) {
|
||||||
retval = OK;
|
retval = OK;
|
||||||
else {
|
} else {
|
||||||
int found = 1;
|
int found = 1;
|
||||||
int cc;
|
int cc;
|
||||||
|
|
||||||
@ -2519,23 +2519,22 @@ static int jumpto_tag(
|
|||||||
*/
|
*/
|
||||||
p_ic = TRUE;
|
p_ic = TRUE;
|
||||||
if (!do_search(NULL, pbuf[0], pbuf + 1, (long)1,
|
if (!do_search(NULL, pbuf[0], pbuf + 1, (long)1,
|
||||||
search_options, NULL)) {
|
search_options, NULL, NULL)) {
|
||||||
/*
|
// Failed to find pattern, take a guess: "^func ("
|
||||||
* Failed to find pattern, take a guess: "^func ("
|
|
||||||
*/
|
|
||||||
found = 2;
|
found = 2;
|
||||||
(void)test_for_static(&tagp);
|
(void)test_for_static(&tagp);
|
||||||
cc = *tagp.tagname_end;
|
cc = *tagp.tagname_end;
|
||||||
*tagp.tagname_end = NUL;
|
*tagp.tagname_end = NUL;
|
||||||
sprintf((char *)pbuf, "^%s\\s\\*(", tagp.tagname);
|
snprintf((char *)pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname);
|
||||||
if (!do_search(NULL, '/', pbuf, (long)1,
|
if (!do_search(NULL, '/', pbuf, (long)1,
|
||||||
search_options, NULL)) {
|
search_options, NULL, NULL)) {
|
||||||
/* Guess again: "^char * \<func (" */
|
// Guess again: "^char * \<func ("
|
||||||
sprintf((char *)pbuf, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(",
|
snprintf((char *)pbuf, LSIZE, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(",
|
||||||
tagp.tagname);
|
tagp.tagname);
|
||||||
if (!do_search(NULL, '/', pbuf, (long)1,
|
if (!do_search(NULL, '/', pbuf, (long)1,
|
||||||
search_options, NULL))
|
search_options, NULL, NULL)) {
|
||||||
found = 0;
|
found = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*tagp.tagname_end = cc;
|
*tagp.tagname_end = cc;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user