mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 8.0.0647: syntax highlighting can make cause a freeze
Problem: Syntax highlighting can make cause a freeze. Solution: Apply 'redrawtime' to syntax highlighting, per window.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
*options.txt* For Vim version 8.0. Last change: 2017 Jun 13
|
||||
*options.txt* For Vim version 8.0. Last change: 2017 Jun 18
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -5945,10 +5945,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
{only available when compiled with the |+reltime|
|
||||
feature}
|
||||
The time in milliseconds for redrawing the display. This applies to
|
||||
searching for patterns for 'hlsearch' and |:match| highlighting.
|
||||
searching for patterns for 'hlsearch', |:match| highlighting an syntax
|
||||
highlighting.
|
||||
When redrawing takes more than this many milliseconds no further
|
||||
matches will be highlighted. This is used to avoid that Vim hangs
|
||||
when using a very complicated pattern.
|
||||
matches will be highlighted.
|
||||
For syntax highlighting the time applies per window. When over the
|
||||
limit syntax highlighting is disabled until |CTRL-L| is used.
|
||||
This is used to avoid that Vim hangs when using a very complicated
|
||||
pattern.
|
||||
|
||||
*'regexpengine'* *'re'*
|
||||
'regexpengine' 're' number (default 0)
|
||||
|
@@ -5477,6 +5477,14 @@ nv_clear(cmdarg_T *cap)
|
||||
#ifdef FEAT_SYN_HL
|
||||
/* Clear all syntax states to force resyncing. */
|
||||
syn_stack_free_all(curwin->w_s);
|
||||
# ifdef FEAT_RELTIME
|
||||
{
|
||||
win_T *wp;
|
||||
|
||||
FOR_ALL_WINDOWS(wp)
|
||||
wp->w_s->b_syn_slow = FALSE;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
redraw_later(CLEAR);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* syntax.c */
|
||||
void syntax_start(win_T *wp, linenr_T lnum);
|
||||
void syntax_start(win_T *wp, linenr_T lnum, proftime_T *syntax_tm);
|
||||
void syn_stack_free_all(synblock_T *block);
|
||||
void syn_stack_apply_changes(buf_T *buf);
|
||||
void syntax_end_parsing(linenr_T lnum);
|
||||
|
12
src/regexp.c
12
src/regexp.c
@@ -5756,8 +5756,6 @@ regmatch(
|
||||
printf("Premature EOL\n");
|
||||
#endif
|
||||
}
|
||||
if (status == RA_FAIL)
|
||||
got_int = TRUE;
|
||||
return (status == RA_MATCH);
|
||||
}
|
||||
|
||||
@@ -8224,8 +8222,6 @@ report_re_switch(char_u *pat)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int vim_regexec_both(regmatch_T *rmp, char_u *line, colnr_T col, int nl);
|
||||
|
||||
/*
|
||||
* Match a regexp against a string.
|
||||
* "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
|
||||
@@ -8236,7 +8232,7 @@ static int vim_regexec_both(regmatch_T *rmp, char_u *line, colnr_T col, int nl);
|
||||
* Return TRUE if there is a match, FALSE if not.
|
||||
*/
|
||||
static int
|
||||
vim_regexec_both(
|
||||
vim_regexec_string(
|
||||
regmatch_T *rmp,
|
||||
char_u *line, /* string to match against */
|
||||
colnr_T col, /* column to start looking for match */
|
||||
@@ -8304,7 +8300,7 @@ vim_regexec_prog(
|
||||
|
||||
regmatch.regprog = *prog;
|
||||
regmatch.rm_ic = ignore_case;
|
||||
r = vim_regexec_both(®match, line, col, FALSE);
|
||||
r = vim_regexec_string(®match, line, col, FALSE);
|
||||
*prog = regmatch.regprog;
|
||||
return r;
|
||||
}
|
||||
@@ -8316,7 +8312,7 @@ vim_regexec_prog(
|
||||
int
|
||||
vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
|
||||
{
|
||||
return vim_regexec_both(rmp, line, col, FALSE);
|
||||
return vim_regexec_string(rmp, line, col, FALSE);
|
||||
}
|
||||
|
||||
#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \
|
||||
@@ -8329,7 +8325,7 @@ vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
|
||||
int
|
||||
vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col)
|
||||
{
|
||||
return vim_regexec_both(rmp, line, col, TRUE);
|
||||
return vim_regexec_string(rmp, line, col, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
59
src/screen.c
59
src/screen.c
@@ -124,7 +124,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
|
||||
static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
|
||||
static void copy_text_attr(int off, char_u *buf, int len, int attr);
|
||||
#endif
|
||||
static int win_line(win_T *, linenr_T, int, int, int nochange);
|
||||
static int win_line(win_T *, linenr_T, int, int, int nochange, proftime_T *syntax_tm);
|
||||
static int char_needs_redraw(int off_from, int off_to, int cols);
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
static void screen_line(int row, int coloff, int endcol, int clear_width, int rlflag);
|
||||
@@ -185,6 +185,11 @@ static void win_redr_ruler(win_T *wp, int always);
|
||||
static int screen_char_attr = 0;
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME)
|
||||
/* Can limit syntax highlight time to 'redrawtime'. */
|
||||
# define SYN_TIME_LIMIT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Redraw the current window later, with update_screen(type).
|
||||
* Set must_redraw only if not already set to a higher value.
|
||||
@@ -923,6 +928,9 @@ update_single_line(win_T *wp, linenr_T lnum)
|
||||
{
|
||||
int row;
|
||||
int j;
|
||||
#ifdef SYN_TIME_LIMIT
|
||||
proftime_T syntax_tm;
|
||||
#endif
|
||||
|
||||
/* Don't do anything if the screen structures are (not yet) valid. */
|
||||
if (!screen_valid(TRUE) || updating_screen)
|
||||
@@ -931,6 +939,10 @@ update_single_line(win_T *wp, linenr_T lnum)
|
||||
if (lnum >= wp->w_topline && lnum < wp->w_botline
|
||||
&& foldedCount(wp, lnum, &win_foldinfo) == 0)
|
||||
{
|
||||
#ifdef SYN_TIME_LIMIT
|
||||
/* Set the time limit to 'redrawtime'. */
|
||||
profile_setlimit(p_rdt, &syntax_tm);
|
||||
#endif
|
||||
update_prepare();
|
||||
|
||||
row = 0;
|
||||
@@ -944,7 +956,13 @@ update_single_line(win_T *wp, linenr_T lnum)
|
||||
start_search_hl();
|
||||
prepare_search_hl(wp, lnum);
|
||||
# endif
|
||||
win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, FALSE);
|
||||
win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, FALSE,
|
||||
#ifdef SYN_TIME_LIMIT
|
||||
&syntax_tm
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
# if defined(FEAT_SEARCH_EXTRA)
|
||||
end_search_hl();
|
||||
# endif
|
||||
@@ -1140,6 +1158,9 @@ win_update(win_T *wp)
|
||||
#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
|
||||
int save_got_int;
|
||||
#endif
|
||||
#ifdef SYN_TIME_LIMIT
|
||||
proftime_T syntax_tm;
|
||||
#endif
|
||||
|
||||
type = wp->w_redr_type;
|
||||
|
||||
@@ -1792,6 +1813,10 @@ win_update(win_T *wp)
|
||||
save_got_int = got_int;
|
||||
got_int = 0;
|
||||
#endif
|
||||
#ifdef SYN_TIME_LIMIT
|
||||
/* Set the time limit to 'redrawtime'. */
|
||||
profile_setlimit(p_rdt, &syntax_tm);
|
||||
#endif
|
||||
#ifdef FEAT_FOLDING
|
||||
win_foldinfo.fi_level = 0;
|
||||
#endif
|
||||
@@ -2086,7 +2111,13 @@ win_update(win_T *wp)
|
||||
/*
|
||||
* Display one line.
|
||||
*/
|
||||
row = win_line(wp, lnum, srow, wp->w_height, mod_top == 0);
|
||||
row = win_line(wp, lnum, srow, wp->w_height, mod_top == 0,
|
||||
#ifdef SYN_TIME_LIMIT
|
||||
&syntax_tm
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
|
||||
#ifdef FEAT_FOLDING
|
||||
wp->w_lines[idx].wl_folded = FALSE;
|
||||
@@ -2957,7 +2988,8 @@ win_line(
|
||||
linenr_T lnum,
|
||||
int startrow,
|
||||
int endrow,
|
||||
int nochange UNUSED) /* not updating for changed text */
|
||||
int nochange UNUSED, /* not updating for changed text */
|
||||
proftime_T *syntax_tm)
|
||||
{
|
||||
int col = 0; /* visual column on screen */
|
||||
unsigned off; /* offset in ScreenLines/ScreenAttrs */
|
||||
@@ -3158,22 +3190,31 @@ win_line(
|
||||
extra_check = 0;
|
||||
#endif
|
||||
#ifdef FEAT_SYN_HL
|
||||
if (syntax_present(wp) && !wp->w_s->b_syn_error)
|
||||
if (syntax_present(wp) && !wp->w_s->b_syn_error
|
||||
# ifdef SYN_TIME_LIMIT
|
||||
&& !wp->w_s->b_syn_slow
|
||||
# endif
|
||||
)
|
||||
{
|
||||
/* Prepare for syntax highlighting in this line. When there is an
|
||||
* error, stop syntax highlighting. */
|
||||
save_did_emsg = did_emsg;
|
||||
did_emsg = FALSE;
|
||||
syntax_start(wp, lnum);
|
||||
syntax_start(wp, lnum, syntax_tm);
|
||||
if (did_emsg)
|
||||
wp->w_s->b_syn_error = TRUE;
|
||||
else
|
||||
{
|
||||
did_emsg = save_did_emsg;
|
||||
#ifdef SYN_TIME_LIMIT
|
||||
if (!wp->w_s->b_syn_slow)
|
||||
#endif
|
||||
{
|
||||
has_syntax = TRUE;
|
||||
extra_check = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for columns to display for 'colorcolumn'. */
|
||||
color_cols = wp->w_p_cc_cols;
|
||||
@@ -3548,7 +3589,7 @@ win_line(
|
||||
# ifdef FEAT_SYN_HL
|
||||
/* Need to restart syntax highlighting for this line. */
|
||||
if (has_syntax)
|
||||
syntax_start(wp, lnum);
|
||||
syntax_start(wp, lnum, syntax_tm);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
@@ -4491,6 +4532,10 @@ win_line(
|
||||
}
|
||||
else
|
||||
did_emsg = save_did_emsg;
|
||||
#ifdef SYN_TIME_LIMIT
|
||||
if (wp->w_s->b_syn_slow)
|
||||
has_syntax = FALSE;
|
||||
#endif
|
||||
|
||||
/* Need to get the line again, a multi-line regexp may
|
||||
* have made it invalid. */
|
||||
|
@@ -1797,6 +1797,9 @@ typedef struct {
|
||||
hashtab_T b_keywtab; /* syntax keywords hash table */
|
||||
hashtab_T b_keywtab_ic; /* idem, ignore case */
|
||||
int b_syn_error; /* TRUE when error occurred in HL */
|
||||
# ifdef FEAT_RELTIME
|
||||
int b_syn_slow; /* TRUE when 'redrawtime' reached */
|
||||
# endif
|
||||
int b_syn_ic; /* ignore case for :syn cmds */
|
||||
int b_syn_spell; /* SYNSPL_ values */
|
||||
garray_T b_syn_patterns; /* table for syntax patterns */
|
||||
|
37
src/syntax.c
37
src/syntax.c
@@ -367,6 +367,9 @@ static reg_extmatch_T *next_match_extmatch = NULL;
|
||||
static win_T *syn_win; /* current window for highlighting */
|
||||
static buf_T *syn_buf; /* current buffer for highlighting */
|
||||
static synblock_T *syn_block; /* current buffer for highlighting */
|
||||
#ifdef FEAT_RELTIME
|
||||
static proftime_T *syn_tm;
|
||||
#endif
|
||||
static linenr_T current_lnum = 0; /* lnum of current state */
|
||||
static colnr_T current_col = 0; /* column of current state */
|
||||
static int current_state_stored = 0; /* TRUE if stored current state
|
||||
@@ -494,7 +497,7 @@ static void syn_incl_toplevel(int id, int *flagsp);
|
||||
* window.
|
||||
*/
|
||||
void
|
||||
syntax_start(win_T *wp, linenr_T lnum)
|
||||
syntax_start(win_T *wp, linenr_T lnum, proftime_T *syntax_tm UNUSED)
|
||||
{
|
||||
synstate_T *p;
|
||||
synstate_T *last_valid = NULL;
|
||||
@@ -524,6 +527,9 @@ syntax_start(win_T *wp, linenr_T lnum)
|
||||
}
|
||||
changedtick = CHANGEDTICK(syn_buf);
|
||||
syn_win = wp;
|
||||
#ifdef FEAT_RELTIME
|
||||
syn_tm = syntax_tm;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate syntax stack when needed.
|
||||
@@ -3295,6 +3301,9 @@ syn_regexec(
|
||||
syn_time_T *st UNUSED)
|
||||
{
|
||||
int r;
|
||||
#ifdef FEAT_RELTIME
|
||||
int timed_out = FALSE;
|
||||
#endif
|
||||
#ifdef FEAT_PROFILE
|
||||
proftime_T pt;
|
||||
|
||||
@@ -3303,7 +3312,13 @@ syn_regexec(
|
||||
#endif
|
||||
|
||||
rmp->rmm_maxcol = syn_buf->b_p_smc;
|
||||
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, NULL, NULL);
|
||||
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col,
|
||||
#ifdef FEAT_RELTIME
|
||||
syn_tm, &timed_out
|
||||
#else
|
||||
NULL, NULL
|
||||
#endif
|
||||
);
|
||||
|
||||
#ifdef FEAT_PROFILE
|
||||
if (syn_time_on)
|
||||
@@ -3317,6 +3332,10 @@ syn_regexec(
|
||||
++st->match;
|
||||
}
|
||||
#endif
|
||||
#ifdef FEAT_RELTIME
|
||||
if (timed_out)
|
||||
syn_win->w_s->b_syn_slow = TRUE;
|
||||
#endif
|
||||
|
||||
if (r > 0)
|
||||
{
|
||||
@@ -3575,6 +3594,9 @@ syntax_clear(synblock_T *block)
|
||||
int i;
|
||||
|
||||
block->b_syn_error = FALSE; /* clear previous error */
|
||||
#ifdef FEAT_RELTIME
|
||||
block->b_syn_slow = FALSE; /* clear previous timeout */
|
||||
#endif
|
||||
block->b_syn_ic = FALSE; /* Use case, by default */
|
||||
block->b_syn_spell = SYNSPL_DEFAULT; /* default spell checking */
|
||||
block->b_syn_containedin = FALSE;
|
||||
@@ -6542,7 +6564,7 @@ syn_get_id(
|
||||
if (wp->w_buffer != syn_buf
|
||||
|| lnum != current_lnum
|
||||
|| col < current_col)
|
||||
syntax_start(wp, lnum);
|
||||
syntax_start(wp, lnum, NULL);
|
||||
else if (wp->w_buffer == syn_buf
|
||||
&& lnum == current_lnum
|
||||
&& col > current_col)
|
||||
@@ -6611,9 +6633,14 @@ syn_get_foldlevel(win_T *wp, long lnum)
|
||||
int i;
|
||||
|
||||
/* Return quickly when there are no fold items at all. */
|
||||
if (wp->w_s->b_syn_folditems != 0)
|
||||
if (wp->w_s->b_syn_folditems != 0
|
||||
&& !wp->w_s->b_syn_error
|
||||
# ifdef SYN_TIME_LIMIT
|
||||
&& !wp->w_s->b_syn_slow
|
||||
# endif
|
||||
)
|
||||
{
|
||||
syntax_start(wp, lnum);
|
||||
syntax_start(wp, lnum, NULL);
|
||||
|
||||
for (i = 0; i < current_state.ga_len; ++i)
|
||||
if (CUR_STATE(i).si_flags & HL_FOLD)
|
||||
|
@@ -424,3 +424,37 @@ func Test_bg_detection()
|
||||
hi Normal ctermbg=12
|
||||
call assert_equal('dark', &bg)
|
||||
endfunc
|
||||
|
||||
func Test_syntax_hangs()
|
||||
if !has('reltime') || !has('float') || !has('syntax')
|
||||
return
|
||||
endif
|
||||
|
||||
" This pattern takes a long time to match, it should timeout.
|
||||
new
|
||||
call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
|
||||
let start = reltime()
|
||||
set nolazyredraw redrawtime=101
|
||||
syn match Error /\%#=1a*.*X\@<=b*/
|
||||
redraw
|
||||
let elapsed = reltimefloat(reltime(start))
|
||||
call assert_true(elapsed > 0.1)
|
||||
call assert_true(elapsed < 1.0)
|
||||
|
||||
" second time syntax HL is disabled
|
||||
let start = reltime()
|
||||
redraw
|
||||
let elapsed = reltimefloat(reltime(start))
|
||||
call assert_true(elapsed < 0.1)
|
||||
|
||||
" after CTRL-L the timeout flag is reset
|
||||
let start = reltime()
|
||||
exe "normal \<C-L>"
|
||||
redraw
|
||||
let elapsed = reltimefloat(reltime(start))
|
||||
call assert_true(elapsed > 0.1)
|
||||
call assert_true(elapsed < 1.0)
|
||||
|
||||
set redrawtime&
|
||||
bwipe!
|
||||
endfunc
|
||||
|
@@ -764,6 +764,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
647,
|
||||
/**/
|
||||
646,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user