Patch 8.0.0647
Problem:    Syntax highlighting can cause a freeze.
Solution:   Apply 'redrawtime' to syntax highlighting, per window.
Files:      src/structs.h, src/screen.c, src/syntax.c, src/normal.c,
            src/regexp.c, src/proto/syntax.pro, src/testdir/test_syntax.vim,
            runtime/doc/options.txt


*** ../vim-8.0.0646/src/structs.h       2017-06-04 14:57:57.308461406 +0200
--- src/structs.h       2017-06-18 22:34:55.806759923 +0200
***************
*** 1797,1802 ****
--- 1797,1805 ----
      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 */
*** ../vim-8.0.0646/src/screen.c        2017-06-17 18:44:16.990001010 +0200
--- src/screen.c        2017-06-18 22:37:21.649768994 +0200
***************
*** 124,130 ****
  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 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);
--- 124,130 ----
  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, 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,190 ****
--- 185,195 ----
  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,928 ****
--- 928,936 ----
  {
      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,936 ****
--- 939,948 ----
      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,950 ****
                start_search_hl();
                prepare_search_hl(wp, lnum);
  # endif
!               win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, FALSE);
  # if defined(FEAT_SEARCH_EXTRA)
                end_search_hl();
  # endif
--- 956,968 ----
                start_search_hl();
                prepare_search_hl(wp, lnum);
  # endif
!               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,1145 ****
--- 1158,1166 ----
  #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,1797 ****
--- 1813,1822 ----
      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,2092 ****
                /*
                 * Display one line.
                 */
!               row = win_line(wp, lnum, srow, wp->w_height, mod_top == 0);
  
  #ifdef FEAT_FOLDING
                wp->w_lines[idx].wl_folded = FALSE;
--- 2111,2123 ----
                /*
                 * Display one line.
                 */
!               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,2963 ****
      linenr_T  lnum,
      int               startrow,
      int               endrow,
!     int               nochange UNUSED)        /* not updating for changed 
text */
  {
      int               col = 0;                /* visual column on screen */
      unsigned  off;                    /* offset in ScreenLines/ScreenAttrs */
--- 2988,2995 ----
      linenr_T  lnum,
      int               startrow,
      int               endrow,
!     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,3177 ****
      extra_check = 0;
  #endif
  #ifdef FEAT_SYN_HL
!     if (syntax_present(wp) && !wp->w_s->b_syn_error)
      {
        /* 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);
        if (did_emsg)
            wp->w_s->b_syn_error = TRUE;
        else
        {
            did_emsg = save_did_emsg;
!           has_syntax = TRUE;
!           extra_check = TRUE;
        }
      }
  
--- 3190,3218 ----
      extra_check = 0;
  #endif
  #ifdef FEAT_SYN_HL
!     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_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;
!           }
        }
      }
  
***************
*** 3548,3554 ****
  # ifdef FEAT_SYN_HL
            /* Need to restart syntax highlighting for this line. */
            if (has_syntax)
!               syntax_start(wp, lnum);
  # endif
        }
  #endif
--- 3589,3595 ----
  # ifdef FEAT_SYN_HL
            /* Need to restart syntax highlighting for this line. */
            if (has_syntax)
!               syntax_start(wp, lnum, syntax_tm);
  # endif
        }
  #endif
***************
*** 4491,4496 ****
--- 4532,4541 ----
                    }
                    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. */
*** ../vim-8.0.0646/src/syntax.c        2017-06-17 18:44:16.998000950 +0200
--- src/syntax.c        2017-06-18 22:34:02.871119550 +0200
***************
*** 367,372 ****
--- 367,375 ----
  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,500 ****
   * window.
   */
      void
! syntax_start(win_T *wp, linenr_T lnum)
  {
      synstate_T        *p;
      synstate_T        *last_valid = NULL;
--- 497,503 ----
   * window.
   */
      void
! syntax_start(win_T *wp, linenr_T lnum, proftime_T *syntax_tm UNUSED)
  {
      synstate_T        *p;
      synstate_T        *last_valid = NULL;
***************
*** 524,529 ****
--- 527,535 ----
      }
      changedtick = CHANGEDTICK(syn_buf);
      syn_win = wp;
+ #ifdef FEAT_RELTIME
+     syn_tm = syntax_tm;
+ #endif
  
      /*
       * Allocate syntax stack when needed.
***************
*** 3295,3300 ****
--- 3301,3309 ----
      syn_time_T  *st UNUSED)
  {
      int r;
+ #ifdef FEAT_RELTIME
+     int timed_out = FALSE;
+ #endif
  #ifdef FEAT_PROFILE
      proftime_T        pt;
  
***************
*** 3303,3309 ****
  #endif
  
      rmp->rmm_maxcol = syn_buf->b_p_smc;
!     r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, NULL, NULL);
  
  #ifdef FEAT_PROFILE
      if (syn_time_on)
--- 3312,3324 ----
  #endif
  
      rmp->rmm_maxcol = syn_buf->b_p_smc;
!     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,3322 ****
--- 3332,3341 ----
            ++st->match;
      }
  #endif
+ #ifdef FEAT_RELTIME
+     if (timed_out)
+       syn_win->w_s->b_syn_slow = TRUE;
+ #endif
  
      if (r > 0)
      {
***************
*** 3575,3580 ****
--- 3594,3602 ----
      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,6548 ****
      if (wp->w_buffer != syn_buf
            || lnum != current_lnum
            || col < current_col)
!       syntax_start(wp, lnum);
      else if (wp->w_buffer == syn_buf
            && lnum == current_lnum
            && col > current_col)
--- 6564,6570 ----
      if (wp->w_buffer != syn_buf
            || lnum != current_lnum
            || col < current_col)
!       syntax_start(wp, lnum, NULL);
      else if (wp->w_buffer == syn_buf
            && lnum == current_lnum
            && col > current_col)
***************
*** 6611,6619 ****
      int               i;
  
      /* Return quickly when there are no fold items at all. */
!     if (wp->w_s->b_syn_folditems != 0)
      {
!       syntax_start(wp, lnum);
  
        for (i = 0; i < current_state.ga_len; ++i)
            if (CUR_STATE(i).si_flags & HL_FOLD)
--- 6633,6646 ----
      int               i;
  
      /* Return quickly when there are no fold items at all. */
!     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, NULL);
  
        for (i = 0; i < current_state.ga_len; ++i)
            if (CUR_STATE(i).si_flags & HL_FOLD)
*** ../vim-8.0.0646/src/normal.c        2017-06-17 18:44:17.006000891 +0200
--- src/normal.c        2017-06-18 21:16:22.014677454 +0200
***************
*** 5477,5482 ****
--- 5477,5490 ----
  #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);
      }
*** ../vim-8.0.0646/src/regexp.c        2017-06-17 20:55:02.560050893 +0200
--- src/regexp.c        2017-06-18 22:23:11.955539687 +0200
***************
*** 5756,5763 ****
            printf("Premature EOL\n");
  #endif
        }
-       if (status == RA_FAIL)
-           got_int = TRUE;
        return (status == RA_MATCH);
      }
  
--- 5756,5761 ----
***************
*** 8224,8231 ****
  }
  #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().
--- 8222,8227 ----
***************
*** 8236,8242 ****
   * Return TRUE if there is a match, FALSE if not.
   */
      static int
! vim_regexec_both(
      regmatch_T        *rmp,
      char_u    *line,  /* string to match against */
      colnr_T   col,    /* column to start looking for match */
--- 8232,8238 ----
   * Return TRUE if there is a match, FALSE if not.
   */
      static int
! vim_regexec_string(
      regmatch_T        *rmp,
      char_u    *line,  /* string to match against */
      colnr_T   col,    /* column to start looking for match */
***************
*** 8299,8310 ****
      char_u    *line,
      colnr_T   col)
  {
!     int r;
!     regmatch_T regmatch;
  
      regmatch.regprog = *prog;
      regmatch.rm_ic = ignore_case;
!     r = vim_regexec_both(&regmatch, line, col, FALSE);
      *prog = regmatch.regprog;
      return r;
  }
--- 8295,8306 ----
      char_u    *line,
      colnr_T   col)
  {
!     int               r;
!     regmatch_T        regmatch;
  
      regmatch.regprog = *prog;
      regmatch.rm_ic = ignore_case;
!     r = vim_regexec_string(&regmatch, line, col, FALSE);
      *prog = regmatch.regprog;
      return r;
  }
***************
*** 8316,8322 ****
      int
  vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
  {
!     return vim_regexec_both(rmp, line, col, FALSE);
  }
  
  #if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \
--- 8312,8318 ----
      int
  vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
  {
!     return vim_regexec_string(rmp, line, col, FALSE);
  }
  
  #if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \
***************
*** 8329,8335 ****
      int
  vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col)
  {
!     return vim_regexec_both(rmp, line, col, TRUE);
  }
  #endif
  
--- 8325,8331 ----
      int
  vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col)
  {
!     return vim_regexec_string(rmp, line, col, TRUE);
  }
  #endif
  
*** ../vim-8.0.0646/src/proto/syntax.pro        2017-03-26 13:50:02.528929457 
+0200
--- src/proto/syntax.pro        2017-06-18 22:02:10.308118953 +0200
***************
*** 1,5 ****
  /* syntax.c */
! void syntax_start(win_T *wp, linenr_T lnum);
  void syn_stack_free_all(synblock_T *block);
  void syn_stack_apply_changes(buf_T *buf);
  void syntax_end_parsing(linenr_T lnum);
--- 1,5 ----
  /* syntax.c */
! 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);
*** ../vim-8.0.0646/src/testdir/test_syntax.vim 2017-06-04 21:06:05.082813802 
+0200
--- src/testdir/test_syntax.vim 2017-06-18 22:11:03.856488746 +0200
***************
*** 424,426 ****
--- 424,460 ----
    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
*** ../vim-8.0.0646/runtime/doc/options.txt     2017-06-13 17:20:35.691782326 
+0200
--- runtime/doc/options.txt     2017-06-18 21:13:04.459998172 +0200
***************
*** 5859,5868 ****
                        {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.
        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.
  
                                                *'regexpengine'* *'re'*
  'regexpengine' 're'   number  (default 0)
--- 5945,5958 ----
                        {only available when compiled with the |+reltime|
                        feature}
        The time in milliseconds for redrawing the display.  This applies to
!       searching for patterns for 'hlsearch', |:match| highlighting an syntax
!       highlighting.
        When redrawing takes more than this many milliseconds no further
!       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)
*** ../vim-8.0.0646/src/version.c       2017-06-17 20:55:02.564050863 +0200
--- src/version.c       2017-06-18 21:11:24.128668186 +0200
***************
*** 766,767 ****
--- 766,769 ----
  {   /* Add new patch number below this line */
+ /**/
+     647,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
42. Your virtual girlfriend finds a new net sweetheart with a larger bandwidth.

 /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui