Permalink
Browse files

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.
  • Loading branch information...
brammool committed Jun 17, 2017
1 parent 8cf9128 commit fbd0b0af6800f6ff89857863d6a07ea03f09ff6c
Showing with 123 additions and 67 deletions.
  1. +1 −1 src/edit.c
  2. +2 −2 src/evalfunc.c
  3. +5 −5 src/ex_cmds.c
  4. +2 −2 src/ex_docmd.c
  5. +3 −3 src/ex_getln.c
  6. +1 −1 src/gui.c
  7. +2 −2 src/normal.c
  8. +1 −1 src/proto/regexp.pro
  9. +2 −2 src/proto/search.pro
  10. +2 −2 src/quickfix.c
  11. +16 −8 src/regexp.c
  12. +2 −2 src/regexp.h
  13. +43 −11 src/regexp_nfa.c
  14. +4 −3 src/screen.c
  15. +29 −16 src/search.c
  16. +1 −1 src/spell.c
  17. +1 −1 src/syntax.c
  18. +4 −4 src/tag.c
  19. +2 −0 src/version.c
View
@@ -4512,7 +4512,7 @@ ins_compl_get_exp(pos_T *ini)
found_new_match = searchit(NULL, ins_buf, pos,
compl_direction,
compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
RE_LAST, (linenr_T)0, NULL);
RE_LAST, (linenr_T)0, NULL, NULL);
--msg_silent;
if (!compl_started || set_match_pos)
{
View
@@ -9281,7 +9281,7 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
pos = save_cursor = curwin->w_cursor;
subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
if (subpatnum != FAIL)
{
if (flags & SP_SUBPAT)
@@ -9619,7 +9619,7 @@ do_searchpair(
for (;;)
{
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 && EQUAL_POS(pos, firstpos)))
/* didn't find it or found the first match again: FAIL */
break;
View
@@ -5096,7 +5096,7 @@ do_sub(exarg_T *eap)
); ++lnum)
{
nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL);
(colnr_T)0, NULL, NULL);
if (nmatch)
{
colnr_T copycol;
@@ -5695,7 +5695,7 @@ do_sub(exarg_T *eap)
|| nmatch_tl > 0
|| (nmatch = vim_regexec_multi(&regmatch, curwin,
curbuf, sub_firstlnum,
matchcol, NULL)) == 0
matchcol, NULL, NULL)) == 0
|| regmatch.startpos[0].lnum > 0)
{
if (new_start != NULL)
@@ -5760,7 +5760,7 @@ do_sub(exarg_T *eap)
}
if (nmatch == -1 && !lastone)
nmatch = vim_regexec_multi(&regmatch, curwin, curbuf,
sub_firstlnum, matchcol, NULL);
sub_firstlnum, matchcol, NULL, NULL);
/*
* 5. break if there isn't another match in this line
@@ -6012,7 +6012,7 @@ ex_global(exarg_T *eap)
{
lnum = curwin->w_cursor.lnum;
match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL);
(colnr_T)0, NULL, NULL);
if ((type == 'g' && match) || (type == 'v' && !match))
global_exe_one(cmd, lnum);
}
@@ -6025,7 +6025,7 @@ ex_global(exarg_T *eap)
{
/* a match on this line? */
match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL);
(colnr_T)0, NULL, NULL);
if ((type == 'g' && match) || (type == 'v' && !match))
{
ml_setmarked(lnum);
View
@@ -4556,7 +4556,7 @@ get_address(
curwin->w_cursor.col = 0;
searchcmdlen = 0;
if (!do_search(NULL, c, cmd, 1L,
SEARCH_HIS | SEARCH_MSG, NULL))
SEARCH_HIS | SEARCH_MSG, NULL, NULL))
{
curwin->w_cursor = pos;
cmd = NULL;
@@ -4613,7 +4613,7 @@ get_address(
if (searchit(curwin, curbuf, &pos,
*cmd == '?' ? BACKWARD : FORWARD,
(char_u *)"", 1L, SEARCH_MSG,
i, (linenr_T)0, NULL) != FAIL)
i, (linenr_T)0, NULL, NULL) != FAIL)
lnum = pos.lnum;
else
{
View
@@ -1693,7 +1693,7 @@ getcmdline(
i = searchit(curwin, curbuf, &t,
c == Ctrl_G ? FORWARD : BACKWARD,
ccline.cmdbuff, count, search_flags,
RE_SEARCH, 0, NULL);
RE_SEARCH, 0, NULL, NULL);
--emsg_off;
if (i)
{
@@ -1903,9 +1903,9 @@ getcmdline(
i = do_search(NULL, firstc, ccline.cmdbuff, count,
SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK,
#ifdef FEAT_RELTIME
&tm
&tm, NULL
#else
NULL
NULL, NULL
#endif
);
--emsg_off;
View
@@ -5361,7 +5361,7 @@ gui_do_findrepl(
searchflags += SEARCH_START;
i = msg_scroll;
(void)do_search(NULL, down ? '/' : '?', ga.ga_data, 1L,
searchflags, NULL);
searchflags, NULL, NULL);
msg_scroll = i; /* don't let an error message set msg_scroll */
}
View
@@ -4358,7 +4358,7 @@ find_decl(
{
valid = FALSE;
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)
t = FAIL; /* match after start is failure too */
@@ -6380,7 +6380,7 @@ normal_search(
curwin->w_set_curswant = TRUE;
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)
clearop(cap->oap);
else
View
@@ -16,5 +16,5 @@ void vim_regfree(regprog_T *prog);
int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col);
int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col);
int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col);
long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm);
long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm, int *timed_out);
/* vim: set ft=c : */
View
@@ -19,9 +19,9 @@ char_u *last_search_pat(void);
void reset_search_dir(void);
void set_last_search_pat(char_u *s, int idx, int magic, int setlast);
void last_pat_prog(regmmatch_T *regmatch);
int searchit(win_T *win, buf_T *buf, pos_T *pos, int dir, char_u *pat, long count, int options, int pat_use, linenr_T stop_lnum, proftime_T *tm);
int searchit(win_T *win, buf_T *buf, pos_T *pos, int dir, char_u *pat, long count, int options, int pat_use, linenr_T stop_lnum, proftime_T *tm, int *timed_out);
void set_search_direction(int cdir);
int do_search(oparg_T *oap, int dirc, char_u *pat, long count, int options, proftime_T *tm);
int do_search(oparg_T *oap, int dirc, char_u *pat, long count, int options, proftime_T *tm, int *timed_out);
int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat);
int searchc(cmdarg_T *cap, int t_cmd);
pos_T *findmatch(oparg_T *oap, int initc);
View
@@ -2415,7 +2415,7 @@ qf_jump(
save_cursor = curwin->w_cursor;
curwin->w_cursor.lnum = 0;
if (!do_search(NULL, '/', qf_ptr->qf_pattern, (long)1,
SEARCH_KEEP, NULL))
SEARCH_KEEP, NULL, NULL))
curwin->w_cursor = save_cursor;
}
@@ -4237,7 +4237,7 @@ ex_vimgrep(exarg_T *eap)
{
col = 0;
while (vim_regexec_multi(&regmatch, curwin, buf, lnum,
col, NULL) > 0)
col, NULL, NULL) > 0)
{
/* Pass the buffer number so that it gets used even for a
* dummy buffer, unless duplicate_name is set, then the
View
@@ -3479,7 +3479,7 @@ typedef struct regbehind_S
} regbehind_T;
static char_u *reg_getline(linenr_T lnum);
static long bt_regexec_both(char_u *line, colnr_T col, proftime_T *tm);
static long bt_regexec_both(char_u *line, colnr_T col, proftime_T *tm, int *timed_out);
static long regtry(bt_regprog_T *prog, colnr_T col);
static void cleanup_subexpr(void);
#ifdef FEAT_SYN_HL
@@ -3722,7 +3722,7 @@ bt_regexec_nl(
#endif
rex.reg_maxcol = 0;
return bt_regexec_both(line, col, NULL);
return bt_regexec_both(line, col, NULL, NULL);
}
/*
@@ -3740,7 +3740,8 @@ bt_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;
@@ -3755,7 +3756,7 @@ bt_regexec_multi(
#endif
rex.reg_maxcol = rmp->rmm_maxcol;
return bt_regexec_both(NULL, col, tm);
return bt_regexec_both(NULL, col, tm, timed_out);
}
/*
@@ -3767,7 +3768,8 @@ bt_regexec_multi(
bt_regexec_both(
char_u *line,
colnr_T col, /* column to start looking for match */
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 */
{
bt_regprog_T *prog;
char_u *s;
@@ -3968,7 +3970,11 @@ bt_regexec_both(
{
tm_count = 0;
if (profile_passed_limit(tm))
{
if (timed_out != NULL)
*timed_out = TRUE;
break;
}
}
#endif
}
@@ -8308,7 +8314,8 @@ vim_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 is set when timeout limit reached */
{
int result;
regexec_T rex_save;
@@ -8319,7 +8326,8 @@ vim_regexec_multi(
rex_save = rex;
rex_in_use = TRUE;
result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col, tm);
result = rmp->regprog->engine->regexec_multi(
rmp, win, buf, lnum, col, tm, timed_out);
/* NFA engine aborted because it's very slow. */
if (rmp->regprog->re_engine == AUTOMATIC_ENGINE
@@ -8339,7 +8347,7 @@ vim_regexec_multi(
rmp->regprog = vim_regcomp(pat, re_flags);
if (rmp->regprog != NULL)
result = rmp->regprog->engine->regexec_multi(
rmp, win, buf, lnum, col, tm);
rmp, win, buf, lnum, col, tm, timed_out);
vim_free(pat);
}
p_re = save_p_re;
View
@@ -165,8 +165,8 @@ struct regengine
{
regprog_T *(*regcomp)(char_u*, int);
void (*regfree)(regprog_T *);
int (*regexec_nl)(regmatch_T*, char_u*, colnr_T, int);
long (*regexec_multi)(regmmatch_T*, win_T*, buf_T*, linenr_T, colnr_T, proftime_T*);
int (*regexec_nl)(regmatch_T *, char_u *, colnr_T, int);
long (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, colnr_T, proftime_T *, int *);
char_u *expr;
};
Oops, something went wrong.

0 comments on commit fbd0b0a

Please sign in to comment.