3838 * in tl_scrollback are no longer used.
3939 *
4040 * TODO:
41+ * - Win32: Termdebug doesn't work, because gdb does not support mi2. This
42+ * plugin: https://github.com/cpiger/NeoDebug runs gdb as a job, redirecting
43+ * input and output. Command I/O is in gdb window.
4144 * - Win32: Redirecting input does not work, half of Test_terminal_redir_file()
4245 * is disabled.
4346 * - Win32: Redirecting output works but includes escape sequences.
@@ -100,6 +103,8 @@ struct terminal_S {
100103
101104 int tl_normal_mode ; /* TRUE: Terminal-Normal mode */
102105 int tl_channel_closed ;
106+ int tl_channel_recently_closed ; // still need to handle tl_finish
107+
103108 int tl_finish ;
104109#define TL_FINISH_UNSET NUL
105110#define TL_FINISH_CLOSE 'c' /* ++close or :terminal without argument */
@@ -971,12 +976,10 @@ write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
971976 if (buffer == curbuf )
972977 {
973978 update_screen (0 );
974- update_cursor (term , TRUE);
975- #ifdef FEAT_GUI_MACVIM
976- /* Force a flush now for better experience of interactive shell. */
977- if (gui .in_use )
978- gui_macvim_force_flush ();
979- #endif
979+ /* update_screen() can be slow, check the terminal wasn't closed
980+ * already */
981+ if (buffer == curbuf && curbuf -> b_term != NULL )
982+ update_cursor (curbuf -> b_term , TRUE);
980983 }
981984 else
982985 redraw_after_callback (TRUE);
@@ -2105,6 +2108,10 @@ terminal_loop(int blocking)
21052108 while (must_redraw != 0 )
21062109 if (update_screen (0 ) == FAIL )
21072110 break ;
2111+ if (!term_use_loop_check (TRUE))
2112+ /* job finished while redrawing */
2113+ break ;
2114+
21082115 update_cursor (curbuf -> b_term , FALSE);
21092116 restore_cursor = TRUE;
21102117
@@ -2774,6 +2781,53 @@ static VTermScreenCallbacks screen_callbacks = {
27742781 NULL /* sb_popline */
27752782};
27762783
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+
27772831/*
27782832 * Called when a channel has been closed.
27792833 * If this was a channel for a terminal window then finish it up.
@@ -2782,9 +2836,12 @@ static VTermScreenCallbacks screen_callbacks = {
27822836term_channel_closed (channel_T * ch )
27832837{
27842838 term_T * term ;
2839+ term_T * next_term ;
27852840 int did_one = FALSE;
27862841
2787- 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 ;
27882845 if (term -> tl_job == ch -> ch_job )
27892846 {
27902847 term -> tl_channel_closed = TRUE;
@@ -2800,43 +2857,19 @@ term_channel_closed(channel_T *ch)
28002857 }
28012858#endif
28022859
2803- /* Unless in Terminal-Normal mode: clear the vterm. */
2804- if (!term -> tl_normal_mode )
2860+ if (updating_screen )
28052861 {
2806- int fnum = term -> tl_buffer -> b_fnum ;
2807-
2808- cleanup_vterm (term );
2809-
2810- if (term -> tl_finish == TL_FINISH_CLOSE )
2811- {
2812- aco_save_T aco ;
2813-
2814- /* ++close or term_finish == "close" */
2815- ch_log (NULL , "terminal job finished, closing window" );
2816- aucmd_prepbuf (& aco , term -> tl_buffer );
2817- do_bufdel (DOBUF_WIPE , (char_u * )"" , 1 , fnum , fnum , FALSE);
2818- aucmd_restbuf (& aco );
2819- break ;
2820- }
2821- if (term -> tl_finish == TL_FINISH_OPEN
2822- && term -> tl_buffer -> b_nwindows == 0 )
2823- {
2824- char buf [50 ];
2825-
2826- /* TODO: use term_opencmd */
2827- ch_log (NULL , "terminal job finished, opening window" );
2828- vim_snprintf (buf , sizeof (buf ),
2829- term -> tl_opencmd == NULL
2830- ? "botright sbuf %d"
2831- : (char * )term -> tl_opencmd , fnum );
2832- do_cmdline_cmd ((char_u * )buf );
2833- }
2834- else
2835- 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 ;
28362866 }
28372867
2838- redraw_buf_and_status_later (term -> tl_buffer , NOT_VALID );
2868+ if (term_after_channel_closed (term ))
2869+ next_term = first_term ;
28392870 }
2871+ }
2872+
28402873 if (did_one )
28412874 {
28422875 redraw_statuslines ();
@@ -2855,6 +2888,29 @@ term_channel_closed(channel_T *ch)
28552888 }
28562889}
28572890
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+
28582914/*
28592915 * Fill one screen line from a line of the terminal.
28602916 * Advances "pos" to past the last column.
0 commit comments