comparison src/terminal.c @ 13888:81e8e6181aeb v8.0.1815

patch 8.0.1815: crash with terminal window and with 'lazyredraw' set commit https://github.com/vim/vim/commit/0cb8ac71ae42f66d525ad855db01361ca38d935a Author: Bram Moolenaar <Bram@vim.org> Date: Fri May 11 22:01:51 2018 +0200 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.
author Christian Brabandt <cb@256bit.org>
date Fri, 11 May 2018 22:15:06 +0200
parents bbf5bdba4a80
children 3969c9d3a859
comparison
equal deleted inserted replaced
13887:f5a2d0eb9926 13888:81e8e6181aeb
101 /* Set when setting the size of a vterm, reset after redrawing. */ 101 /* Set when setting the size of a vterm, reset after redrawing. */
102 int tl_vterm_size_changed; 102 int tl_vterm_size_changed;
103 103
104 int tl_normal_mode; /* TRUE: Terminal-Normal mode */ 104 int tl_normal_mode; /* TRUE: Terminal-Normal mode */
105 int tl_channel_closed; 105 int tl_channel_closed;
106 int tl_channel_recently_closed; // still need to handle tl_finish
107
106 int tl_finish; 108 int tl_finish;
107 #define TL_FINISH_UNSET NUL 109 #define TL_FINISH_UNSET NUL
108 #define TL_FINISH_CLOSE 'c' /* ++close or :terminal without argument */ 110 #define TL_FINISH_CLOSE 'c' /* ++close or :terminal without argument */
109 #define TL_FINISH_NOCLOSE 'n' /* ++noclose */ 111 #define TL_FINISH_NOCLOSE 'n' /* ++noclose */
110 #define TL_FINISH_OPEN 'o' /* ++open */ 112 #define TL_FINISH_OPEN 'o' /* ++open */
2778 handle_pushline, /* sb_pushline */ 2780 handle_pushline, /* sb_pushline */
2779 NULL /* sb_popline */ 2781 NULL /* sb_popline */
2780 }; 2782 };
2781 2783
2782 /* 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
2831 /*
2783 * Called when a channel has been closed. 2832 * Called when a channel has been closed.
2784 * If this was a channel for a terminal window then finish it up. 2833 * If this was a channel for a terminal window then finish it up.
2785 */ 2834 */
2786 void 2835 void
2787 term_channel_closed(channel_T *ch) 2836 term_channel_closed(channel_T *ch)
2788 { 2837 {
2789 term_T *term; 2838 term_T *term;
2839 term_T *next_term;
2790 int did_one = FALSE; 2840 int did_one = FALSE;
2791 2841
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;
2793 if (term->tl_job == ch->ch_job) 2845 if (term->tl_job == ch->ch_job)
2794 { 2846 {
2795 term->tl_channel_closed = TRUE; 2847 term->tl_channel_closed = TRUE;
2796 did_one = TRUE; 2848 did_one = TRUE;
2797 2849
2803 fclose(term->tl_out_fd); 2855 fclose(term->tl_out_fd);
2804 term->tl_out_fd = NULL; 2856 term->tl_out_fd = NULL;
2805 } 2857 }
2806 #endif 2858 #endif
2807 2859
2808 /* Unless in Terminal-Normal mode: clear the vterm. */ 2860 if (updating_screen)
2809 if (!term->tl_normal_mode)
2810 { 2861 {
2811 int fnum = term->tl_buffer->b_fnum; 2862 /* Cannot open or close windows now. Can happen when
2812 2863 * 'lazyredraw' is set. */
2813 cleanup_vterm(term); 2864 term->tl_channel_recently_closed = TRUE;
2814 2865 continue;
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");
2841 } 2866 }
2842 2867
2843 redraw_buf_and_status_later(term->tl_buffer, NOT_VALID); 2868 if (term_after_channel_closed(term))
2844 } 2869 next_term = first_term;
2870 }
2871 }
2872
2845 if (did_one) 2873 if (did_one)
2846 { 2874 {
2847 redraw_statuslines(); 2875 redraw_statuslines();
2848 2876
2849 /* Need to break out of vgetc(). */ 2877 /* Need to break out of vgetc(). */
2854 if (term != NULL) 2882 if (term != NULL)
2855 { 2883 {
2856 if (term->tl_job == ch->ch_job) 2884 if (term->tl_job == ch->ch_job)
2857 maketitle(); 2885 maketitle();
2858 update_cursor(term, term->tl_cursor_visible); 2886 update_cursor(term, term->tl_cursor_visible);
2887 }
2888 }
2889 }
2890
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;
2859 } 2910 }
2860 } 2911 }
2861 } 2912 }
2862 2913
2863 /* 2914 /*