comparison src/terminal.c @ 15826:1f2edc01e7ed v8.1.0920

patch 8.1.0920: in Terminal-Normal mode job output messes up the window commit https://github.com/vim/vim/commit/29ae223ddcfcbbce46c7e1f4e8fa71b8f2674271 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Feb 14 21:22:01 2019 +0100 patch 8.1.0920: in Terminal-Normal mode job output messes up the window Problem: In Terminal-Normal mode job output messes up the window. Solution: Postpone scrolling and updating the buffer when in Terminal-Normal mode.
author Bram Moolenaar <Bram@vim.org>
date Thu, 14 Feb 2019 21:30:05 +0100
parents 5523665fdf80
children 8f112782a2e9
comparison
equal deleted inserted replaced
15825:c2cac058bb49 15826:1f2edc01e7ed
58 VTermColor fg; 58 VTermColor fg;
59 VTermColor bg; 59 VTermColor bg;
60 } cellattr_T; 60 } cellattr_T;
61 61
62 typedef struct sb_line_S { 62 typedef struct sb_line_S {
63 int sb_cols; /* can differ per line */ 63 int sb_cols; // can differ per line
64 cellattr_T *sb_cells; /* allocated */ 64 cellattr_T *sb_cells; // allocated
65 cellattr_T sb_fill_attr; /* for short line */ 65 cellattr_T sb_fill_attr; // for short line
66 char_u *sb_text; // for tl_scrollback_postponed
66 } sb_line_T; 67 } sb_line_T;
67 68
68 #ifdef WIN3264 69 #ifdef WIN3264
69 # ifndef HPCON 70 # ifndef HPCON
70 # define HPCON VOID* 71 # define HPCON VOID*
142 #endif 143 #endif
143 int tl_postponed_scroll; /* to be scrolled up */ 144 int tl_postponed_scroll; /* to be scrolled up */
144 145
145 garray_T tl_scrollback; 146 garray_T tl_scrollback;
146 int tl_scrollback_scrolled; 147 int tl_scrollback_scrolled;
148 garray_T tl_scrollback_postponed;
149
147 cellattr_T tl_default_color; 150 cellattr_T tl_default_color;
148 151
149 linenr_T tl_top_diff_rows; /* rows of top diff file or zero */ 152 linenr_T tl_top_diff_rows; /* rows of top diff file or zero */
150 linenr_T tl_bot_diff_rows; /* rows of bottom diff file */ 153 linenr_T tl_bot_diff_rows; /* rows of bottom diff file */
151 154
185 static void term_report_winsize(term_T *term, int rows, int cols); 188 static void term_report_winsize(term_T *term, int rows, int cols);
186 static void term_free_vterm(term_T *term); 189 static void term_free_vterm(term_T *term);
187 #ifdef FEAT_GUI 190 #ifdef FEAT_GUI
188 static void update_system_term(term_T *term); 191 static void update_system_term(term_T *term);
189 #endif 192 #endif
193
194 static void handle_postponed_scrollback(term_T *term);
190 195
191 /* The character that we know (or assume) that the terminal expects for the 196 /* The character that we know (or assume) that the terminal expects for the
192 * backspace key. */ 197 * backspace key. */
193 static int term_backspace_char = BS; 198 static int term_backspace_char = BS;
194 199
417 term->tl_finish = opt->jo_term_finish; 422 term->tl_finish = opt->jo_term_finish;
418 #ifdef FEAT_GUI 423 #ifdef FEAT_GUI
419 term->tl_system = (flags & TERM_START_SYSTEM); 424 term->tl_system = (flags & TERM_START_SYSTEM);
420 #endif 425 #endif
421 ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300); 426 ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
427 ga_init2(&term->tl_scrollback_postponed, sizeof(sb_line_T), 300);
422 428
423 vim_memset(&split_ea, 0, sizeof(split_ea)); 429 vim_memset(&split_ea, 0, sizeof(split_ea));
424 if (opt->jo_curwin) 430 if (opt->jo_curwin)
425 { 431 {
426 /* Create a new buffer in the current window. */ 432 /* Create a new buffer in the current window. */
850 int i; 856 int i;
851 857
852 for (i = 0; i < term->tl_scrollback.ga_len; ++i) 858 for (i = 0; i < term->tl_scrollback.ga_len; ++i)
853 vim_free(((sb_line_T *)term->tl_scrollback.ga_data + i)->sb_cells); 859 vim_free(((sb_line_T *)term->tl_scrollback.ga_data + i)->sb_cells);
854 ga_clear(&term->tl_scrollback); 860 ga_clear(&term->tl_scrollback);
861 for (i = 0; i < term->tl_scrollback_postponed.ga_len; ++i)
862 vim_free(((sb_line_T *)term->tl_scrollback_postponed.ga_data + i)->sb_cells);
863 ga_clear(&term->tl_scrollback_postponed);
855 } 864 }
856 865
857 866
858 // Terminals that need to be freed soon. 867 // Terminals that need to be freed soon.
859 term_T *terminals_to_free = NULL; 868 term_T *terminals_to_free = NULL;
1768 1777
1769 return next_due; 1778 return next_due;
1770 } 1779 }
1771 #endif 1780 #endif
1772 1781
1782 /*
1783 * When "normal_mode" is TRUE set the terminal to Terminal-Normal mode,
1784 * otherwise end it.
1785 */
1773 static void 1786 static void
1774 set_terminal_mode(term_T *term, int normal_mode) 1787 set_terminal_mode(term_T *term, int normal_mode)
1775 { 1788 {
1789 ch_log(NULL, "set_terminal_mode(): %d", normal_mode);
1776 term->tl_normal_mode = normal_mode; 1790 term->tl_normal_mode = normal_mode;
1791 if (!normal_mode)
1792 handle_postponed_scrollback(term);
1777 VIM_CLEAR(term->tl_status_text); 1793 VIM_CLEAR(term->tl_status_text);
1778 if (term->tl_buffer == curbuf) 1794 if (term->tl_buffer == curbuf)
1779 maketitle(); 1795 maketitle();
1780 } 1796 }
1781 1797
1784 * Move the vterm contents into the scrollback buffer and free the vterm. 1800 * Move the vterm contents into the scrollback buffer and free the vterm.
1785 */ 1801 */
1786 static void 1802 static void
1787 cleanup_vterm(term_T *term) 1803 cleanup_vterm(term_T *term)
1788 { 1804 {
1805 set_terminal_mode(term, FALSE);
1789 if (term->tl_finish != TL_FINISH_CLOSE) 1806 if (term->tl_finish != TL_FINISH_CLOSE)
1790 may_move_terminal_to_buffer(term, TRUE); 1807 may_move_terminal_to_buffer(term, TRUE);
1791 term_free_vterm(term); 1808 term_free_vterm(term);
1792 set_terminal_mode(term, FALSE);
1793 } 1809 }
1794 1810
1795 /* 1811 /*
1796 * Switch from Terminal-Job mode to Terminal-Normal mode. 1812 * Switch from Terminal-Job mode to Terminal-Normal mode.
1797 * Suspends updating the terminal window. 1813 * Suspends updating the terminal window.
2789 } 2805 }
2790 return 1; 2806 return 1;
2791 } 2807 }
2792 2808
2793 /* 2809 /*
2810 * If the number of lines that are stored goes over 'termscrollback' then
2811 * delete the first 10%.
2812 * "gap" points to tl_scrollback or tl_scrollback_postponed.
2813 * "update_buffer" is TRUE when the buffer should be updated.
2814 */
2815 static void
2816 limit_scrollback(term_T *term, garray_T *gap, int update_buffer)
2817 {
2818 if (gap->ga_len >= term->tl_buffer->b_p_twsl)
2819 {
2820 int todo = term->tl_buffer->b_p_twsl / 10;
2821 int i;
2822
2823 curbuf = term->tl_buffer;
2824 for (i = 0; i < todo; ++i)
2825 {
2826 vim_free(((sb_line_T *)gap->ga_data + i)->sb_cells);
2827 if (update_buffer)
2828 ml_delete(1, FALSE);
2829 }
2830 curbuf = curwin->w_buffer;
2831
2832 gap->ga_len -= todo;
2833 mch_memmove(gap->ga_data,
2834 (sb_line_T *)gap->ga_data + todo,
2835 sizeof(sb_line_T) * gap->ga_len);
2836 if (update_buffer)
2837 term->tl_scrollback_scrolled -= todo;
2838 }
2839 }
2840
2841 /*
2794 * Handle a line that is pushed off the top of the screen. 2842 * Handle a line that is pushed off the top of the screen.
2795 */ 2843 */
2796 static int 2844 static int
2797 handle_pushline(int cols, const VTermScreenCell *cells, void *user) 2845 handle_pushline(int cols, const VTermScreenCell *cells, void *user)
2798 { 2846 {
2799 term_T *term = (term_T *)user; 2847 term_T *term = (term_T *)user;
2800 2848 garray_T *gap;
2801 /* First remove the lines that were appended before, the pushed line goes 2849 int update_buffer;
2802 * above it. */ 2850
2803 cleanup_scrollback(term); 2851 if (term->tl_normal_mode)
2804 2852 {
2805 /* If the number of lines that are stored goes over 'termscrollback' then 2853 // In Terminal-Normal mode the user interacts with the buffer, thus we
2806 * delete the first 10%. */ 2854 // must not change it. Postpone adding the scrollback lines.
2807 if (term->tl_scrollback.ga_len >= term->tl_buffer->b_p_twsl) 2855 gap = &term->tl_scrollback_postponed;
2808 { 2856 update_buffer = FALSE;
2809 int todo = term->tl_buffer->b_p_twsl / 10; 2857 ch_log(NULL, "handle_pushline(): add to postponed");
2810 int i; 2858 }
2811 2859 else
2812 curbuf = term->tl_buffer; 2860 {
2813 for (i = 0; i < todo; ++i) 2861 // First remove the lines that were appended before, the pushed line
2814 { 2862 // goes above it.
2815 vim_free(((sb_line_T *)term->tl_scrollback.ga_data + i)->sb_cells); 2863 cleanup_scrollback(term);
2816 ml_delete(1, FALSE); 2864 gap = &term->tl_scrollback;
2817 } 2865 update_buffer = TRUE;
2818 curbuf = curwin->w_buffer; 2866 ch_log(NULL, "handle_pushline(): add to window");
2819 2867 }
2820 term->tl_scrollback.ga_len -= todo; 2868
2821 mch_memmove(term->tl_scrollback.ga_data, 2869 limit_scrollback(term, gap, update_buffer);
2822 (sb_line_T *)term->tl_scrollback.ga_data + todo, 2870
2823 sizeof(sb_line_T) * term->tl_scrollback.ga_len); 2871 if (ga_grow(gap, 1) == OK)
2824 term->tl_scrollback_scrolled -= todo;
2825 }
2826
2827 if (ga_grow(&term->tl_scrollback, 1) == OK)
2828 { 2872 {
2829 cellattr_T *p = NULL; 2873 cellattr_T *p = NULL;
2830 int len = 0; 2874 int len = 0;
2831 int i; 2875 int i;
2832 int c; 2876 int c;
2833 int col; 2877 int col;
2878 int text_len;
2879 char_u *text;
2834 sb_line_T *line; 2880 sb_line_T *line;
2835 garray_T ga; 2881 garray_T ga;
2836 cellattr_T fill_attr = term->tl_default_color; 2882 cellattr_T fill_attr = term->tl_default_color;
2837 2883
2838 /* do not store empty cells at the end */ 2884 // do not store empty cells at the end
2839 for (i = 0; i < cols; ++i) 2885 for (i = 0; i < cols; ++i)
2840 if (cells[i].chars[0] != 0) 2886 if (cells[i].chars[0] != 0)
2841 len = i + 1; 2887 len = i + 1;
2842 else 2888 else
2843 cell2cellattr(&cells[i], &fill_attr); 2889 cell2cellattr(&cells[i], &fill_attr);
2859 (char_u *)ga.ga_data + ga.ga_len); 2905 (char_u *)ga.ga_data + ga.ga_len);
2860 cell2cellattr(&cells[col], &p[col]); 2906 cell2cellattr(&cells[col], &p[col]);
2861 } 2907 }
2862 } 2908 }
2863 if (ga_grow(&ga, 1) == FAIL) 2909 if (ga_grow(&ga, 1) == FAIL)
2864 add_scrollback_line_to_buffer(term, (char_u *)"", 0); 2910 {
2911 if (update_buffer)
2912 text = (char_u *)"";
2913 else
2914 text = vim_strsave((char_u *)"");
2915 text_len = 0;
2916 }
2865 else 2917 else
2866 { 2918 {
2867 *((char_u *)ga.ga_data + ga.ga_len) = NUL; 2919 text = ga.ga_data;
2868 add_scrollback_line_to_buffer(term, ga.ga_data, ga.ga_len); 2920 text_len = ga.ga_len;
2869 } 2921 *(text + text_len) = NUL;
2870 ga_clear(&ga); 2922 }
2871 2923 if (update_buffer)
2872 line = (sb_line_T *)term->tl_scrollback.ga_data 2924 add_scrollback_line_to_buffer(term, text, text_len);
2873 + term->tl_scrollback.ga_len; 2925
2926 line = (sb_line_T *)gap->ga_data + gap->ga_len;
2874 line->sb_cols = len; 2927 line->sb_cols = len;
2875 line->sb_cells = p; 2928 line->sb_cells = p;
2876 line->sb_fill_attr = fill_attr; 2929 line->sb_fill_attr = fill_attr;
2930 if (update_buffer)
2931 {
2932 line->sb_text = NULL;
2933 ++term->tl_scrollback_scrolled;
2934 ga_clear(&ga); // free the text
2935 }
2936 else
2937 {
2938 line->sb_text = text;
2939 ga_init(&ga); // text is kept in tl_scrollback_postponed
2940 }
2941 ++gap->ga_len;
2942 }
2943 return 0; /* ignored */
2944 }
2945
2946 /*
2947 * Called when leaving Terminal-Normal mode: deal with any scrollback that was
2948 * received and stored in tl_scrollback_postponed.
2949 */
2950 static void
2951 handle_postponed_scrollback(term_T *term)
2952 {
2953 int i;
2954
2955 ch_log(NULL, "Moving postponed scrollback to scrollback");
2956 // First remove the lines that were appended before, the pushed lines go
2957 // above it.
2958 cleanup_scrollback(term);
2959
2960 for (i = 0; i < term->tl_scrollback_postponed.ga_len; ++i)
2961 {
2962 char_u *text;
2963 sb_line_T *pp_line;
2964 sb_line_T *line;
2965
2966 if (ga_grow(&term->tl_scrollback, 1) == FAIL)
2967 break;
2968 pp_line = (sb_line_T *)term->tl_scrollback_postponed.ga_data + i;
2969
2970 text = pp_line->sb_text;
2971 if (text == NULL)
2972 text = (char_u *)"";
2973 add_scrollback_line_to_buffer(term, text, (int)STRLEN(text));
2974 vim_free(pp_line->sb_text);
2975
2976 line = (sb_line_T *)term->tl_scrollback.ga_data
2977 + term->tl_scrollback.ga_len;
2978 line->sb_cols = pp_line->sb_cols;
2979 line->sb_cells = pp_line->sb_cells;
2980 line->sb_fill_attr = pp_line->sb_fill_attr;
2981 line->sb_text = NULL;
2982 ++term->tl_scrollback_scrolled;
2877 ++term->tl_scrollback.ga_len; 2983 ++term->tl_scrollback.ga_len;
2878 ++term->tl_scrollback_scrolled; 2984 }
2879 } 2985
2880 return 0; /* ignored */ 2986 ga_clear(&term->tl_scrollback_postponed);
2987 limit_scrollback(term, &term->tl_scrollback, TRUE);
2881 } 2988 }
2882 2989
2883 static VTermScreenCallbacks screen_callbacks = { 2990 static VTermScreenCallbacks screen_callbacks = {
2884 handle_damage, /* damage */ 2991 handle_damage, /* damage */
2885 handle_moverect, /* moverect */ 2992 handle_moverect, /* moverect */