@@ -103,6 +103,8 @@ struct terminal_S {
103103
104104 int tl_normal_mode ; /* TRUE: Terminal-Normal mode */
105105 int tl_channel_closed ;
106+ int tl_channel_recently_closed ; // still need to handle tl_finish
107+
106108 int tl_finish ;
107109#define TL_FINISH_UNSET NUL
108110#define TL_FINISH_CLOSE 'c' /* ++close or :terminal without argument */
@@ -2779,6 +2781,53 @@ static VTermScreenCallbacks screen_callbacks = {
27792781 NULL /* sb_popline */
27802782};
27812783
2784+ /*
2785+ * Do the work after the channel of a terminal was closed.
2786+ * Must be called only when updating_screen is FALSE.
2787+ * Returns TRUE when a buffer was closed (list of terminals may have changed).
2788+ */
2789+ static int
2790+ term_after_channel_closed (term_T * term )
2791+ {
2792+ /* Unless in Terminal-Normal mode: clear the vterm. */
2793+ if (!term -> tl_normal_mode )
2794+ {
2795+ int fnum = term -> tl_buffer -> b_fnum ;
2796+
2797+ cleanup_vterm (term );
2798+
2799+ if (term -> tl_finish == TL_FINISH_CLOSE )
2800+ {
2801+ aco_save_T aco ;
2802+
2803+ /* ++close or term_finish == "close" */
2804+ ch_log (NULL , "terminal job finished, closing window" );
2805+ aucmd_prepbuf (& aco , term -> tl_buffer );
2806+ do_bufdel (DOBUF_WIPE , (char_u * )"" , 1 , fnum , fnum , FALSE);
2807+ aucmd_restbuf (& aco );
2808+ return TRUE;
2809+ }
2810+ if (term -> tl_finish == TL_FINISH_OPEN
2811+ && term -> tl_buffer -> b_nwindows == 0 )
2812+ {
2813+ char buf [50 ];
2814+
2815+ /* TODO: use term_opencmd */
2816+ ch_log (NULL , "terminal job finished, opening window" );
2817+ vim_snprintf (buf , sizeof (buf ),
2818+ term -> tl_opencmd == NULL
2819+ ? "botright sbuf %d"
2820+ : (char * )term -> tl_opencmd , fnum );
2821+ do_cmdline_cmd ((char_u * )buf );
2822+ }
2823+ else
2824+ ch_log (NULL , "terminal job finished" );
2825+ }
2826+
2827+ redraw_buf_and_status_later (term -> tl_buffer , NOT_VALID );
2828+ return FALSE;
2829+ }
2830+
27822831/*
27832832 * Called when a channel has been closed.
27842833 * If this was a channel for a terminal window then finish it up.
@@ -2787,9 +2836,12 @@ static VTermScreenCallbacks screen_callbacks = {
27872836term_channel_closed (channel_T * ch )
27882837{
27892838 term_T * term ;
2839+ term_T * next_term ;
27902840 int did_one = FALSE;
27912841
2792- for (term = first_term ; term != NULL ; term = term -> tl_next )
2842+ for (term = first_term ; term != NULL ; term = next_term )
2843+ {
2844+ next_term = term -> tl_next ;
27932845 if (term -> tl_job == ch -> ch_job )
27942846 {
27952847 term -> tl_channel_closed = TRUE;
@@ -2805,43 +2857,19 @@ term_channel_closed(channel_T *ch)
28052857 }
28062858#endif
28072859
2808- /* Unless in Terminal-Normal mode: clear the vterm. */
2809- if (!term -> tl_normal_mode )
2860+ if (updating_screen )
28102861 {
2811- int fnum = term -> tl_buffer -> b_fnum ;
2812-
2813- cleanup_vterm (term );
2814-
2815- if (term -> tl_finish == TL_FINISH_CLOSE )
2816- {
2817- aco_save_T aco ;
2818-
2819- /* ++close or term_finish == "close" */
2820- ch_log (NULL , "terminal job finished, closing window" );
2821- aucmd_prepbuf (& aco , term -> tl_buffer );
2822- do_bufdel (DOBUF_WIPE , (char_u * )"" , 1 , fnum , fnum , FALSE);
2823- aucmd_restbuf (& aco );
2824- break ;
2825- }
2826- if (term -> tl_finish == TL_FINISH_OPEN
2827- && term -> tl_buffer -> b_nwindows == 0 )
2828- {
2829- char buf [50 ];
2830-
2831- /* TODO: use term_opencmd */
2832- ch_log (NULL , "terminal job finished, opening window" );
2833- vim_snprintf (buf , sizeof (buf ),
2834- term -> tl_opencmd == NULL
2835- ? "botright sbuf %d"
2836- : (char * )term -> tl_opencmd , fnum );
2837- do_cmdline_cmd ((char_u * )buf );
2838- }
2839- else
2840- ch_log (NULL , "terminal job finished" );
2862+ /* Cannot open or close windows now. Can happen when
2863+ * 'lazyredraw' is set. */
2864+ term -> tl_channel_recently_closed = TRUE;
2865+ continue ;
28412866 }
28422867
2843- redraw_buf_and_status_later (term -> tl_buffer , NOT_VALID );
2868+ if (term_after_channel_closed (term ))
2869+ next_term = first_term ;
28442870 }
2871+ }
2872+
28452873 if (did_one )
28462874 {
28472875 redraw_statuslines ();
@@ -2860,6 +2888,29 @@ term_channel_closed(channel_T *ch)
28602888 }
28612889}
28622890
2891+ /*
2892+ * To be called after resetting updating_screen: handle any terminal where the
2893+ * channel was closed.
2894+ */
2895+ void
2896+ term_check_channel_closed_recently ()
2897+ {
2898+ term_T * term ;
2899+ term_T * next_term ;
2900+
2901+ for (term = first_term ; term != NULL ; term = next_term )
2902+ {
2903+ next_term = term -> tl_next ;
2904+ if (term -> tl_channel_recently_closed )
2905+ {
2906+ term -> tl_channel_recently_closed = FALSE;
2907+ if (term_after_channel_closed (term ))
2908+ // start over, the list may have changed
2909+ next_term = first_term ;
2910+ }
2911+ }
2912+ }
2913+
28632914/*
28642915 * Fill one screen line from a line of the terminal.
28652916 * Advances "pos" to past the last column.
0 commit comments