Skip to content

Commit 06f1ed2

Browse files
committed
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.
1 parent 0946326 commit 06f1ed2

File tree

9 files changed

+148
-29
lines changed

9 files changed

+148
-29
lines changed

runtime/doc/options.txt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*options.txt* For Vim version 8.0. Last change: 2017 Jun 13
1+
*options.txt* For Vim version 8.0. Last change: 2017 Jun 18
22

33

44
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|.
59455945
{only available when compiled with the |+reltime|
59465946
feature}
59475947
The time in milliseconds for redrawing the display. This applies to
5948-
searching for patterns for 'hlsearch' and |:match| highlighting.
5948+
searching for patterns for 'hlsearch', |:match| highlighting an syntax
5949+
highlighting.
59495950
When redrawing takes more than this many milliseconds no further
5950-
matches will be highlighted. This is used to avoid that Vim hangs
5951-
when using a very complicated pattern.
5951+
matches will be highlighted.
5952+
For syntax highlighting the time applies per window. When over the
5953+
limit syntax highlighting is disabled until |CTRL-L| is used.
5954+
This is used to avoid that Vim hangs when using a very complicated
5955+
pattern.
59525956

59535957
*'regexpengine'* *'re'*
59545958
'regexpengine' 're' number (default 0)

src/normal.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5477,6 +5477,14 @@ nv_clear(cmdarg_T *cap)
54775477
#ifdef FEAT_SYN_HL
54785478
/* Clear all syntax states to force resyncing. */
54795479
syn_stack_free_all(curwin->w_s);
5480+
# ifdef FEAT_RELTIME
5481+
{
5482+
win_T *wp;
5483+
5484+
FOR_ALL_WINDOWS(wp)
5485+
wp->w_s->b_syn_slow = FALSE;
5486+
}
5487+
# endif
54805488
#endif
54815489
redraw_later(CLEAR);
54825490
}

src/proto/syntax.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* syntax.c */
2-
void syntax_start(win_T *wp, linenr_T lnum);
2+
void syntax_start(win_T *wp, linenr_T lnum, proftime_T *syntax_tm);
33
void syn_stack_free_all(synblock_T *block);
44
void syn_stack_apply_changes(buf_T *buf);
55
void syntax_end_parsing(linenr_T lnum);

src/regexp.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5756,8 +5756,6 @@ regmatch(
57565756
printf("Premature EOL\n");
57575757
#endif
57585758
}
5759-
if (status == RA_FAIL)
5760-
got_int = TRUE;
57615759
return (status == RA_MATCH);
57625760
}
57635761

@@ -8224,8 +8222,6 @@ report_re_switch(char_u *pat)
82248222
}
82258223
#endif
82268224

8227-
static int vim_regexec_both(regmatch_T *rmp, char_u *line, colnr_T col, int nl);
8228-
82298225
/*
82308226
* Match a regexp against a string.
82318227
* "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);
82368232
* Return TRUE if there is a match, FALSE if not.
82378233
*/
82388234
static int
8239-
vim_regexec_both(
8235+
vim_regexec_string(
82408236
regmatch_T *rmp,
82418237
char_u *line, /* string to match against */
82428238
colnr_T col, /* column to start looking for match */
@@ -8299,12 +8295,12 @@ vim_regexec_prog(
82998295
char_u *line,
83008296
colnr_T col)
83018297
{
8302-
int r;
8303-
regmatch_T regmatch;
8298+
int r;
8299+
regmatch_T regmatch;
83048300

83058301
regmatch.regprog = *prog;
83068302
regmatch.rm_ic = ignore_case;
8307-
r = vim_regexec_both(&regmatch, line, col, FALSE);
8303+
r = vim_regexec_string(&regmatch, line, col, FALSE);
83088304
*prog = regmatch.regprog;
83098305
return r;
83108306
}
@@ -8316,7 +8312,7 @@ vim_regexec_prog(
83168312
int
83178313
vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
83188314
{
8319-
return vim_regexec_both(rmp, line, col, FALSE);
8315+
return vim_regexec_string(rmp, line, col, FALSE);
83208316
}
83218317

83228318
#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \
@@ -8329,7 +8325,7 @@ vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
83298325
int
83308326
vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col)
83318327
{
8332-
return vim_regexec_both(rmp, line, col, TRUE);
8328+
return vim_regexec_string(rmp, line, col, TRUE);
83338329
}
83348330
#endif
83358331

src/screen.c

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
124124
static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
125125
static void copy_text_attr(int off, char_u *buf, int len, int attr);
126126
#endif
127-
static int win_line(win_T *, linenr_T, int, int, int nochange);
127+
static int win_line(win_T *, linenr_T, int, int, int nochange, proftime_T *syntax_tm);
128128
static int char_needs_redraw(int off_from, int off_to, int cols);
129129
#ifdef FEAT_RIGHTLEFT
130130
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);
185185
static int screen_char_attr = 0;
186186
#endif
187187

188+
#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME)
189+
/* Can limit syntax highlight time to 'redrawtime'. */
190+
# define SYN_TIME_LIMIT 1
191+
#endif
192+
188193
/*
189194
* Redraw the current window later, with update_screen(type).
190195
* 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)
923928
{
924929
int row;
925930
int j;
931+
#ifdef SYN_TIME_LIMIT
932+
proftime_T syntax_tm;
933+
#endif
926934

927935
/* Don't do anything if the screen structures are (not yet) valid. */
928936
if (!screen_valid(TRUE) || updating_screen)
@@ -931,6 +939,10 @@ update_single_line(win_T *wp, linenr_T lnum)
931939
if (lnum >= wp->w_topline && lnum < wp->w_botline
932940
&& foldedCount(wp, lnum, &win_foldinfo) == 0)
933941
{
942+
#ifdef SYN_TIME_LIMIT
943+
/* Set the time limit to 'redrawtime'. */
944+
profile_setlimit(p_rdt, &syntax_tm);
945+
#endif
934946
update_prepare();
935947

936948
row = 0;
@@ -944,7 +956,13 @@ update_single_line(win_T *wp, linenr_T lnum)
944956
start_search_hl();
945957
prepare_search_hl(wp, lnum);
946958
# endif
947-
win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, FALSE);
959+
win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, FALSE,
960+
#ifdef SYN_TIME_LIMIT
961+
&syntax_tm
962+
#else
963+
NULL
964+
#endif
965+
);
948966
# if defined(FEAT_SEARCH_EXTRA)
949967
end_search_hl();
950968
# endif
@@ -1140,6 +1158,9 @@ win_update(win_T *wp)
11401158
#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
11411159
int save_got_int;
11421160
#endif
1161+
#ifdef SYN_TIME_LIMIT
1162+
proftime_T syntax_tm;
1163+
#endif
11431164

11441165
type = wp->w_redr_type;
11451166

@@ -1792,6 +1813,10 @@ win_update(win_T *wp)
17921813
save_got_int = got_int;
17931814
got_int = 0;
17941815
#endif
1816+
#ifdef SYN_TIME_LIMIT
1817+
/* Set the time limit to 'redrawtime'. */
1818+
profile_setlimit(p_rdt, &syntax_tm);
1819+
#endif
17951820
#ifdef FEAT_FOLDING
17961821
win_foldinfo.fi_level = 0;
17971822
#endif
@@ -2086,7 +2111,13 @@ win_update(win_T *wp)
20862111
/*
20872112
* Display one line.
20882113
*/
2089-
row = win_line(wp, lnum, srow, wp->w_height, mod_top == 0);
2114+
row = win_line(wp, lnum, srow, wp->w_height, mod_top == 0,
2115+
#ifdef SYN_TIME_LIMIT
2116+
&syntax_tm
2117+
#else
2118+
NULL
2119+
#endif
2120+
);
20902121

20912122
#ifdef FEAT_FOLDING
20922123
wp->w_lines[idx].wl_folded = FALSE;
@@ -2957,7 +2988,8 @@ win_line(
29572988
linenr_T lnum,
29582989
int startrow,
29592990
int endrow,
2960-
int nochange UNUSED) /* not updating for changed text */
2991+
int nochange UNUSED, /* not updating for changed text */
2992+
proftime_T *syntax_tm)
29612993
{
29622994
int col = 0; /* visual column on screen */
29632995
unsigned off; /* offset in ScreenLines/ScreenAttrs */
@@ -3158,20 +3190,29 @@ win_line(
31583190
extra_check = 0;
31593191
#endif
31603192
#ifdef FEAT_SYN_HL
3161-
if (syntax_present(wp) && !wp->w_s->b_syn_error)
3193+
if (syntax_present(wp) && !wp->w_s->b_syn_error
3194+
# ifdef SYN_TIME_LIMIT
3195+
&& !wp->w_s->b_syn_slow
3196+
# endif
3197+
)
31623198
{
31633199
/* Prepare for syntax highlighting in this line. When there is an
31643200
* error, stop syntax highlighting. */
31653201
save_did_emsg = did_emsg;
31663202
did_emsg = FALSE;
3167-
syntax_start(wp, lnum);
3203+
syntax_start(wp, lnum, syntax_tm);
31683204
if (did_emsg)
31693205
wp->w_s->b_syn_error = TRUE;
31703206
else
31713207
{
31723208
did_emsg = save_did_emsg;
3173-
has_syntax = TRUE;
3174-
extra_check = TRUE;
3209+
#ifdef SYN_TIME_LIMIT
3210+
if (!wp->w_s->b_syn_slow)
3211+
#endif
3212+
{
3213+
has_syntax = TRUE;
3214+
extra_check = TRUE;
3215+
}
31753216
}
31763217
}
31773218

@@ -3548,7 +3589,7 @@ win_line(
35483589
# ifdef FEAT_SYN_HL
35493590
/* Need to restart syntax highlighting for this line. */
35503591
if (has_syntax)
3551-
syntax_start(wp, lnum);
3592+
syntax_start(wp, lnum, syntax_tm);
35523593
# endif
35533594
}
35543595
#endif
@@ -4491,6 +4532,10 @@ win_line(
44914532
}
44924533
else
44934534
did_emsg = save_did_emsg;
4535+
#ifdef SYN_TIME_LIMIT
4536+
if (wp->w_s->b_syn_slow)
4537+
has_syntax = FALSE;
4538+
#endif
44944539

44954540
/* Need to get the line again, a multi-line regexp may
44964541
* have made it invalid. */

src/structs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,6 +1797,9 @@ typedef struct {
17971797
hashtab_T b_keywtab; /* syntax keywords hash table */
17981798
hashtab_T b_keywtab_ic; /* idem, ignore case */
17991799
int b_syn_error; /* TRUE when error occurred in HL */
1800+
# ifdef FEAT_RELTIME
1801+
int b_syn_slow; /* TRUE when 'redrawtime' reached */
1802+
# endif
18001803
int b_syn_ic; /* ignore case for :syn cmds */
18011804
int b_syn_spell; /* SYNSPL_ values */
18021805
garray_T b_syn_patterns; /* table for syntax patterns */

src/syntax.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@ static reg_extmatch_T *next_match_extmatch = NULL;
367367
static win_T *syn_win; /* current window for highlighting */
368368
static buf_T *syn_buf; /* current buffer for highlighting */
369369
static synblock_T *syn_block; /* current buffer for highlighting */
370+
#ifdef FEAT_RELTIME
371+
static proftime_T *syn_tm;
372+
#endif
370373
static linenr_T current_lnum = 0; /* lnum of current state */
371374
static colnr_T current_col = 0; /* column of current state */
372375
static int current_state_stored = 0; /* TRUE if stored current state
@@ -494,7 +497,7 @@ static void syn_incl_toplevel(int id, int *flagsp);
494497
* window.
495498
*/
496499
void
497-
syntax_start(win_T *wp, linenr_T lnum)
500+
syntax_start(win_T *wp, linenr_T lnum, proftime_T *syntax_tm UNUSED)
498501
{
499502
synstate_T *p;
500503
synstate_T *last_valid = NULL;
@@ -524,6 +527,9 @@ syntax_start(win_T *wp, linenr_T lnum)
524527
}
525528
changedtick = CHANGEDTICK(syn_buf);
526529
syn_win = wp;
530+
#ifdef FEAT_RELTIME
531+
syn_tm = syntax_tm;
532+
#endif
527533

528534
/*
529535
* Allocate syntax stack when needed.
@@ -3295,6 +3301,9 @@ syn_regexec(
32953301
syn_time_T *st UNUSED)
32963302
{
32973303
int r;
3304+
#ifdef FEAT_RELTIME
3305+
int timed_out = FALSE;
3306+
#endif
32983307
#ifdef FEAT_PROFILE
32993308
proftime_T pt;
33003309

@@ -3303,7 +3312,13 @@ syn_regexec(
33033312
#endif
33043313

33053314
rmp->rmm_maxcol = syn_buf->b_p_smc;
3306-
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, NULL, NULL);
3315+
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col,
3316+
#ifdef FEAT_RELTIME
3317+
syn_tm, &timed_out
3318+
#else
3319+
NULL, NULL
3320+
#endif
3321+
);
33073322

33083323
#ifdef FEAT_PROFILE
33093324
if (syn_time_on)
@@ -3317,6 +3332,10 @@ syn_regexec(
33173332
++st->match;
33183333
}
33193334
#endif
3335+
#ifdef FEAT_RELTIME
3336+
if (timed_out)
3337+
syn_win->w_s->b_syn_slow = TRUE;
3338+
#endif
33203339

33213340
if (r > 0)
33223341
{
@@ -3575,6 +3594,9 @@ syntax_clear(synblock_T *block)
35753594
int i;
35763595

35773596
block->b_syn_error = FALSE; /* clear previous error */
3597+
#ifdef FEAT_RELTIME
3598+
block->b_syn_slow = FALSE; /* clear previous timeout */
3599+
#endif
35783600
block->b_syn_ic = FALSE; /* Use case, by default */
35793601
block->b_syn_spell = SYNSPL_DEFAULT; /* default spell checking */
35803602
block->b_syn_containedin = FALSE;
@@ -6542,7 +6564,7 @@ syn_get_id(
65426564
if (wp->w_buffer != syn_buf
65436565
|| lnum != current_lnum
65446566
|| col < current_col)
6545-
syntax_start(wp, lnum);
6567+
syntax_start(wp, lnum, NULL);
65466568
else if (wp->w_buffer == syn_buf
65476569
&& lnum == current_lnum
65486570
&& col > current_col)
@@ -6611,9 +6633,14 @@ syn_get_foldlevel(win_T *wp, long lnum)
66116633
int i;
66126634

66136635
/* Return quickly when there are no fold items at all. */
6614-
if (wp->w_s->b_syn_folditems != 0)
6636+
if (wp->w_s->b_syn_folditems != 0
6637+
&& !wp->w_s->b_syn_error
6638+
# ifdef SYN_TIME_LIMIT
6639+
&& !wp->w_s->b_syn_slow
6640+
# endif
6641+
)
66156642
{
6616-
syntax_start(wp, lnum);
6643+
syntax_start(wp, lnum, NULL);
66176644

66186645
for (i = 0; i < current_state.ga_len; ++i)
66196646
if (CUR_STATE(i).si_flags & HL_FOLD)

0 commit comments

Comments
 (0)