To: vim_dev@googlegroups.com Subject: Patch 8.0.1797 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.1797 Problem: Terminal window is redrawn too often and scrolling is repeated. Solution: Don't scroll immediately but only when redrawing. Avoid redrawing the whole terminal window on every change. Files: src/terminal.c, src/screen.c, src/proto/terminal.pro *** ../vim-8.0.1796/src/terminal.c 2018-05-06 13:53:46.374938177 +0200 --- src/terminal.c 2018-05-06 16:38:36.516316098 +0200 *************** *** 42,50 **** * redirection. Probably in call to channel_set_pipes(). * - Win32: Redirecting output does not work, Test_terminal_redir_file() * is disabled. - * - handle_moverect() scrolls one line at a time. Postpone scrolling, count - * the number of lines, until a redraw happens. Then if scrolling many lines - * a redraw is faster. * - Copy text in the vterm to the Vim buffer once in a while, so that * completion works. * - When the job only outputs lines, we could handle resizing the terminal --- 42,47 ---- *************** *** 137,142 **** --- 134,141 ---- int tl_dirty_row_start; /* MAX_ROW if nothing dirty */ int tl_dirty_row_end; /* row below last one to update */ + int tl_postponed_scroll; /* to be scrolled up */ + garray_T tl_scrollback; int tl_scrollback_scrolled; cellattr_T tl_default_color; *************** *** 2373,2416 **** term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row); term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row); ! redraw_buf_later(term->tl_buffer, NOT_VALID); return 1; } static int handle_moverect(VTermRect dest, VTermRect src, void *user) { term_T *term = (term_T *)user; /* Scrolling up is done much more efficiently by deleting lines instead of ! * redrawing the text. */ if (dest.start_col == src.start_col && dest.end_col == src.end_col && dest.start_row < src.start_row) { ! win_T *wp; ! VTermColor fg, bg; ! VTermScreenCellAttrs attr; ! int clear_attr; ! ! /* Set the color to clear lines with. */ ! vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm), ! &fg, &bg); ! vim_memset(&attr, 0, sizeof(attr)); ! clear_attr = cell2attr(attr, fg, bg); ! ! FOR_ALL_WINDOWS(wp) ! { ! if (wp->w_buffer == term->tl_buffer) ! win_del_lines(wp, dest.start_row, ! src.start_row - dest.start_row, FALSE, FALSE, ! clear_attr); ! } } term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, dest.start_row); term->tl_dirty_row_end = MIN(term->tl_dirty_row_end, dest.end_row); redraw_buf_later(term->tl_buffer, NOT_VALID); return 1; } --- 2372,2426 ---- term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row); term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row); ! redraw_buf_later(term->tl_buffer, SOME_VALID); return 1; } + static void + term_scroll_up(term_T *term, int start_row, int count) + { + win_T *wp; + VTermColor fg, bg; + VTermScreenCellAttrs attr; + int clear_attr; + + /* Set the color to clear lines with. */ + vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm), + &fg, &bg); + vim_memset(&attr, 0, sizeof(attr)); + clear_attr = cell2attr(attr, fg, bg); + + FOR_ALL_WINDOWS(wp) + { + if (wp->w_buffer == term->tl_buffer) + win_del_lines(wp, start_row, count, FALSE, FALSE, clear_attr); + } + } + static int handle_moverect(VTermRect dest, VTermRect src, void *user) { term_T *term = (term_T *)user; + int count = src.start_row - dest.start_row; /* Scrolling up is done much more efficiently by deleting lines instead of ! * redrawing the text. But avoid doing this multiple times, postpone until ! * the redraw happens. */ if (dest.start_col == src.start_col && dest.end_col == src.end_col && dest.start_row < src.start_row) { ! if (dest.start_row == 0) ! term->tl_postponed_scroll += count; ! else ! term_scroll_up(term, dest.start_row, count); } term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, dest.start_row); term->tl_dirty_row_end = MIN(term->tl_dirty_row_end, dest.end_row); + /* Note sure if the scrolling will work correctly, let's do a complete + * redraw later. */ redraw_buf_later(term->tl_buffer, NOT_VALID); return 1; } *************** *** 2857,2867 **** #endif /* ! * Called to update a window that contains an active terminal. ! * Returns FAIL when there is no terminal running in this window or in * Terminal-Normal mode. */ int term_update_window(win_T *wp) { term_T *term = wp->w_buffer->b_term; --- 2867,2888 ---- #endif /* ! * Return TRUE if window "wp" is to be redrawn with term_update_window(). ! * Returns FALSE when there is no terminal running in this window or it is in * Terminal-Normal mode. */ int + term_do_update_window(win_T *wp) + { + term_T *term = wp->w_buffer->b_term; + + return term != NULL && term->tl_vterm != NULL && !term->tl_normal_mode; + } + + /* + * Called to update a window that contains an active terminal. + */ + void term_update_window(win_T *wp) { term_T *term = wp->w_buffer->b_term; *************** *** 2874,2890 **** int minsize; win_T *twp; - if (term == NULL || term->tl_vterm == NULL || term->tl_normal_mode) - return FAIL; - vterm = term->tl_vterm; screen = vterm_obtain_screen(vterm); state = vterm_obtain_state(vterm); ! if (wp->w_redr_type >= SOME_VALID) { term->tl_dirty_row_start = 0; term->tl_dirty_row_end = MAX_ROW; } /* --- 2895,2917 ---- int minsize; win_T *twp; vterm = term->tl_vterm; screen = vterm_obtain_screen(vterm); state = vterm_obtain_state(vterm); ! /* We use NOT_VALID on a resize or scroll, redraw everything then. With ! * SOME_VALID only redraw what was marked dirty. */ ! if (wp->w_redr_type > SOME_VALID) { term->tl_dirty_row_start = 0; term->tl_dirty_row_end = MAX_ROW; + + if (term->tl_postponed_scroll > 0 + && term->tl_postponed_scroll < term->tl_rows / 3) + /* Scrolling is usually faster than redrawing, when there are only + * a few lines to scroll. */ + term_scroll_up(term, 0, term->tl_postponed_scroll); + term->tl_postponed_scroll = 0; } /* *************** *** 2943,2950 **** } term->tl_dirty_row_start = MAX_ROW; term->tl_dirty_row_end = 0; - - return OK; } /* --- 2970,2975 ---- *** ../vim-8.0.1796/src/screen.c 2018-04-27 22:53:03.930590711 +0200 --- src/screen.c 2018-05-06 16:30:59.487900163 +0200 *************** *** 567,574 **** must_redraw = 0; } ! /* Need to update w_lines[]. */ ! if (curwin->w_lines_valid == 0 && type < NOT_VALID) type = NOT_VALID; /* Postpone the redrawing when it's not needed and when being called --- 567,578 ---- must_redraw = 0; } ! /* May need to update w_lines[]. */ ! if (curwin->w_lines_valid == 0 && type < NOT_VALID ! #ifdef FEAT_TERMINAL ! && !term_do_update_window(curwin) ! #endif ! ) type = NOT_VALID; /* Postpone the redrawing when it's not needed and when being called *************** *** 1172,1181 **** } #ifdef FEAT_TERMINAL ! /* If this window contains a terminal, redraw works completely differently. ! */ ! if (term_update_window(wp) == OK) { # ifdef FEAT_MENU /* Draw the window toolbar, if there is one. */ if (winbar_height(wp) > 0) --- 1176,1185 ---- } #ifdef FEAT_TERMINAL ! // If this window contains a terminal, redraw works completely differently. ! if (term_do_update_window(wp)) { + term_update_window(wp); # ifdef FEAT_MENU /* Draw the window toolbar, if there is one. */ if (winbar_height(wp) > 0) *** ../vim-8.0.1796/src/proto/terminal.pro 2018-04-14 17:05:29.787581114 +0200 --- src/proto/terminal.pro 2018-05-06 16:30:55.115937396 +0200 *************** *** 14,25 **** int send_keys_to_term(term_T *term, int c, int typed); int terminal_is_active(void); cursorentry_T *term_get_cursor_shape(guicolor_T *fg, guicolor_T *bg); - void term_win_entered(void); int term_use_loop(void); int terminal_loop(int blocking); void term_job_ended(job_T *job); void term_channel_closed(channel_T *ch); ! int term_update_window(win_T *wp); int term_is_finished(buf_T *buf); int term_show_buffer(buf_T *buf); void term_change_in_curbuf(void); --- 14,26 ---- int send_keys_to_term(term_T *term, int c, int typed); int terminal_is_active(void); cursorentry_T *term_get_cursor_shape(guicolor_T *fg, guicolor_T *bg); int term_use_loop(void); + void term_win_entered(void); int terminal_loop(int blocking); void term_job_ended(job_T *job); void term_channel_closed(channel_T *ch); ! int term_do_update_window(win_T *wp); ! void term_update_window(win_T *wp); int term_is_finished(buf_T *buf); int term_show_buffer(buf_T *buf); void term_change_in_curbuf(void); *** ../vim-8.0.1796/src/version.c 2018-05-06 13:53:46.378938152 +0200 --- src/version.c 2018-05-06 16:39:05.092106787 +0200 *************** *** 763,764 **** --- 763,766 ---- { /* Add new patch number below this line */ + /**/ + 1797, /**/ -- I'm sure that I asked CBuilder to do a "full" install. Looks like I got a "fool" install, instead. Charles E Campbell, Jr, PhD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///