]> granicus.if.org Git - vim/commitdiff
patch 8.0.1815: crash with terminal window and with 'lazyredraw' set v8.0.1815
authorBram Moolenaar <Bram@vim.org>
Fri, 11 May 2018 20:01:51 +0000 (22:01 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 11 May 2018 20:01:51 +0000 (22:01 +0200)
Problem:    Still a crash with terminal window and with 'lazyredraw' set.
            (Antoine)
Solution:   Do not wipe out the buffer when updating the screen.

src/proto/screen.pro
src/proto/terminal.pro
src/screen.c
src/terminal.c
src/ui.c
src/version.c

index f690f93d62328a070d913525b0738e2b6c88822b..5760dae1b3cbe80e620da52ca9831644d79cbc20 100644 (file)
@@ -9,6 +9,7 @@ void redraw_buf_and_status_later(buf_T *buf, int type);
 int redraw_asap(int type);
 void redraw_after_callback(int call_update_screen);
 void redrawWinline(linenr_T lnum, int invalid);
+void reset_updating_screen(int may_resize_shell);
 void update_curbuf(int type);
 int update_screen(int type_arg);
 int conceal_cursor_line(win_T *wp);
index 93c6ab53c6cad7645f38d831488c17fd7361cafe..25f9647f25759e40640e4481dfa134bb38387c33 100644 (file)
@@ -20,6 +20,7 @@ void term_win_entered(void);
 int terminal_loop(int blocking);
 void term_job_ended(job_T *job);
 void term_channel_closed(channel_T *ch);
+void term_check_channel_closed_recently(void);
 int term_do_update_window(win_T *wp);
 void term_update_window(win_T *wp);
 int term_is_finished(buf_T *buf);
index cac5a3a1f8685fa5a026c9628efec56f37702a3d..841dc18669f4a36857f32240aed603501d2d2c3a 100644 (file)
@@ -512,6 +512,19 @@ redrawWinline(
            curwin->w_lines[i].wl_valid = FALSE;
     }
 #endif
+}
+
+    void
+reset_updating_screen(int may_resize_shell UNUSED)
+{
+    updating_screen = FALSE;
+#ifdef FEAT_GUI
+    if (may_resize_shell)
+       gui_may_resize_shell();
+#endif
+#ifdef FEAT_TERMINAL
+    term_check_channel_closed_recently();
+#endif
 }
 
 /*
@@ -778,10 +791,7 @@ update_screen(int type_arg)
     FOR_ALL_WINDOWS(wp)
        wp->w_buffer->b_mod_set = FALSE;
 
-    updating_screen = FALSE;
-#ifdef FEAT_GUI
-    gui_may_resize_shell();
-#endif
+    reset_updating_screen(TRUE);
 
     /* Clear or redraw the command line.  Done last, because scrolling may
      * mess up the command line. */
@@ -861,11 +871,9 @@ update_finish(void)
     end_search_hl();
 # endif
 
-    updating_screen = FALSE;
+    reset_updating_screen(TRUE);
 
 # ifdef FEAT_GUI
-    gui_may_resize_shell();
-
     /* Redraw the cursor and update the scrollbars when all screen updating is
      * done. */
     if (gui.in_use)
index 8deac9da867de9f4f256c0904f0d34874b3d9e38..1991f382f38cc0f9ae880ededa1b937c361d8429 100644 (file)
@@ -103,6 +103,8 @@ struct terminal_S {
 
     int                tl_normal_mode; /* TRUE: Terminal-Normal mode */
     int                tl_channel_closed;
+    int                tl_channel_recently_closed; // still need to handle tl_finish
+
     int                tl_finish;
 #define TL_FINISH_UNSET            NUL
 #define TL_FINISH_CLOSE            'c' /* ++close or :terminal without argument */
@@ -2779,6 +2781,53 @@ static VTermScreenCallbacks screen_callbacks = {
   NULL                 /* sb_popline */
 };
 
+/*
+ * Do the work after the channel of a terminal was closed.
+ * Must be called only when updating_screen is FALSE.
+ * Returns TRUE when a buffer was closed (list of terminals may have changed).
+ */
+    static int
+term_after_channel_closed(term_T *term)
+{
+    /* Unless in Terminal-Normal mode: clear the vterm. */
+    if (!term->tl_normal_mode)
+    {
+       int     fnum = term->tl_buffer->b_fnum;
+
+       cleanup_vterm(term);
+
+       if (term->tl_finish == TL_FINISH_CLOSE)
+       {
+           aco_save_T  aco;
+
+           /* ++close or term_finish == "close" */
+           ch_log(NULL, "terminal job finished, closing window");
+           aucmd_prepbuf(&aco, term->tl_buffer);
+           do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
+           aucmd_restbuf(&aco);
+           return TRUE;
+       }
+       if (term->tl_finish == TL_FINISH_OPEN
+                                  && term->tl_buffer->b_nwindows == 0)
+       {
+           char buf[50];
+
+           /* TODO: use term_opencmd */
+           ch_log(NULL, "terminal job finished, opening window");
+           vim_snprintf(buf, sizeof(buf),
+                   term->tl_opencmd == NULL
+                           ? "botright sbuf %d"
+                           : (char *)term->tl_opencmd, fnum);
+           do_cmdline_cmd((char_u *)buf);
+       }
+       else
+           ch_log(NULL, "terminal job finished");
+    }
+
+    redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
+    return FALSE;
+}
+
 /*
  * Called when a channel has been closed.
  * If this was a channel for a terminal window then finish it up.
@@ -2787,9 +2836,12 @@ static VTermScreenCallbacks screen_callbacks = {
 term_channel_closed(channel_T *ch)
 {
     term_T *term;
+    term_T *next_term;
     int            did_one = FALSE;
 
-    for (term = first_term; term != NULL; term = term->tl_next)
+    for (term = first_term; term != NULL; term = next_term)
+    {
+       next_term = term->tl_next;
        if (term->tl_job == ch->ch_job)
        {
            term->tl_channel_closed = TRUE;
@@ -2805,43 +2857,19 @@ term_channel_closed(channel_T *ch)
            }
 #endif
 
-           /* Unless in Terminal-Normal mode: clear the vterm. */
-           if (!term->tl_normal_mode)
+           if (updating_screen)
            {
-               int     fnum = term->tl_buffer->b_fnum;
-
-               cleanup_vterm(term);
-
-               if (term->tl_finish == TL_FINISH_CLOSE)
-               {
-                   aco_save_T  aco;
-
-                   /* ++close or term_finish == "close" */
-                   ch_log(NULL, "terminal job finished, closing window");
-                   aucmd_prepbuf(&aco, term->tl_buffer);
-                   do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
-                   aucmd_restbuf(&aco);
-                   break;
-               }
-               if (term->tl_finish == TL_FINISH_OPEN
-                                          && term->tl_buffer->b_nwindows == 0)
-               {
-                   char buf[50];
-
-                   /* TODO: use term_opencmd */
-                   ch_log(NULL, "terminal job finished, opening window");
-                   vim_snprintf(buf, sizeof(buf),
-                           term->tl_opencmd == NULL
-                                   ? "botright sbuf %d"
-                                   : (char *)term->tl_opencmd, fnum);
-                   do_cmdline_cmd((char_u *)buf);
-               }
-               else
-                   ch_log(NULL, "terminal job finished");
+               /* Cannot open or close windows now.  Can happen when
+                * 'lazyredraw' is set. */
+               term->tl_channel_recently_closed = TRUE;
+               continue;
            }
 
-           redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
+           if (term_after_channel_closed(term))
+               next_term = first_term;
        }
+    }
+
     if (did_one)
     {
        redraw_statuslines();
@@ -2860,6 +2888,29 @@ term_channel_closed(channel_T *ch)
     }
 }
 
+/*
+ * To be called after resetting updating_screen: handle any terminal where the
+ * channel was closed.
+ */
+    void
+term_check_channel_closed_recently()
+{
+    term_T *term;
+    term_T *next_term;
+
+    for (term = first_term; term != NULL; term = next_term)
+    {
+       next_term = term->tl_next;
+       if (term->tl_channel_recently_closed)
+       {
+           term->tl_channel_recently_closed = FALSE;
+           if (term_after_channel_closed(term))
+               // start over, the list may have changed
+               next_term = first_term;
+       }
+    }
+}
+
 /*
  * Fill one screen line from a line of the terminal.
  * Advances "pos" to past the last column.
index 05e82e6c7438d43931550ba672957e91769add09..8e3f0deee1c1955938c7ae4726fce4b50c384c06 100644 (file)
--- a/src/ui.c
+++ b/src/ui.c
@@ -415,7 +415,10 @@ ui_breakcheck_force(int force)
 #endif
        mch_breakcheck(force);
 
-    updating_screen = save_us;
+    if (save_us)
+       updating_screen = save_us;
+    else
+       reset_updating_screen(FALSE);
 }
 
 /*****************************************************************************
index 918e192748605d8c9797e551fbde41ccb831a14c..6346e62171daf12a8eac32d1b562cc742e8104a4 100644 (file)
@@ -761,6 +761,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1815,
 /**/
     1814,
 /**/