Skip to content

Commit 0cb8ac7

Browse files
committed
patch 8.0.1815: crash with terminal window and with 'lazyredraw' set
Problem: Still a crash with terminal window and with 'lazyredraw' set. (Antoine) Solution: Do not wipe out the buffer when updating the screen.
1 parent a10ae5e commit 0cb8ac7

6 files changed

Lines changed: 108 additions & 42 deletions

File tree

src/proto/screen.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ void redraw_buf_and_status_later(buf_T *buf, int type);
99
int redraw_asap(int type);
1010
void redraw_after_callback(int call_update_screen);
1111
void redrawWinline(linenr_T lnum, int invalid);
12+
void reset_updating_screen(int may_resize_shell);
1213
void update_curbuf(int type);
1314
int update_screen(int type_arg);
1415
int conceal_cursor_line(win_T *wp);

src/proto/terminal.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ void term_win_entered(void);
2020
int terminal_loop(int blocking);
2121
void term_job_ended(job_T *job);
2222
void term_channel_closed(channel_T *ch);
23+
void term_check_channel_closed_recently(void);
2324
int term_do_update_window(win_T *wp);
2425
void term_update_window(win_T *wp);
2526
int term_is_finished(buf_T *buf);

src/screen.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,19 @@ redrawWinline(
512512
curwin->w_lines[i].wl_valid = FALSE;
513513
}
514514
#endif
515+
}
516+
517+
void
518+
reset_updating_screen(int may_resize_shell UNUSED)
519+
{
520+
updating_screen = FALSE;
521+
#ifdef FEAT_GUI
522+
if (may_resize_shell)
523+
gui_may_resize_shell();
524+
#endif
525+
#ifdef FEAT_TERMINAL
526+
term_check_channel_closed_recently();
527+
#endif
515528
}
516529

517530
/*
@@ -778,10 +791,7 @@ update_screen(int type_arg)
778791
FOR_ALL_WINDOWS(wp)
779792
wp->w_buffer->b_mod_set = FALSE;
780793

781-
updating_screen = FALSE;
782-
#ifdef FEAT_GUI
783-
gui_may_resize_shell();
784-
#endif
794+
reset_updating_screen(TRUE);
785795

786796
/* Clear or redraw the command line. Done last, because scrolling may
787797
* mess up the command line. */
@@ -861,11 +871,9 @@ update_finish(void)
861871
end_search_hl();
862872
# endif
863873

864-
updating_screen = FALSE;
874+
reset_updating_screen(TRUE);
865875

866876
# ifdef FEAT_GUI
867-
gui_may_resize_shell();
868-
869877
/* Redraw the cursor and update the scrollbars when all screen updating is
870878
* done. */
871879
if (gui.in_use)

src/terminal.c

Lines changed: 85 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -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 = {
27872836
term_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.

src/ui.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,10 @@ ui_breakcheck_force(int force)
415415
#endif
416416
mch_breakcheck(force);
417417

418-
updating_screen = save_us;
418+
if (save_us)
419+
updating_screen = save_us;
420+
else
421+
reset_updating_screen(FALSE);
419422
}
420423

421424
/*****************************************************************************

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,8 @@ static char *(features[]) =
761761

762762
static int included_patches[] =
763763
{ /* Add new patch number below this line */
764+
/**/
765+
1815,
764766
/**/
765767
1814,
766768
/**/

0 commit comments

Comments
 (0)