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