Mercurial > vim
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 /* |