diff --git a/src/terminal.c b/src/terminal.c index aaf30a1832..734282c825 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -4008,8 +4008,11 @@ update_system_term(term_T *term) screen = vterm_obtain_screen(term->tl_vterm); // Scroll up to make more room for terminal lines if needed. + // Use the cursor position to determine how much to scroll, because + // ConPTY may damage all rows on initialization even when most are + // empty, which would cause unnecessary scrolling. while (term->tl_toprow > 0 - && (Rows - term->tl_toprow) < term->tl_dirty_row_end) + && (Rows - term->tl_toprow) < term->tl_cursor_pos.row + 1) { int save_p_more = p_more; diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim index 67b0500aa6..0b0eb02715 100644 --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -960,6 +960,47 @@ func Test_gui_run_cmd_in_terminal() let &guioptions = save_guioptions endfunc +" Test that :! with guioptions+=! doesn't scroll more than necessary. +" With ConPTY on Windows 11, the terminal may damage all rows on init, +" which previously caused the entire screen to scroll up. +func Test_gui_system_term_scroll() + CheckFeature terminal + CheckFeature conpty + let save_guioptions = &guioptions + set guioptions+=! + + enew + call setline(1, repeat(['AAAA'], &lines + 5)) + redraw + + " Timer fires during terminal_loop to check the screen while the command + " is still running. Row 1 should still show buffer content if scrolling + " is correct. + let g:system_term_row1 = '' + func s:CheckScroll(timer) + let g:system_term_row1 = screenstring(1, 1) + endfunc + call timer_start(200, function('s:CheckScroll')) + + " Use a command that runs long enough for the timer to fire during + " terminal_loop. wait_return() returns immediately when sourcing a script, + " so the timer must fire before the command finishes. + if has('win32') + !ping -n 2 127.0.0.1 > nul + else + !sleep 1 + endif + + " With the ConPTY scroll bug, the screen scrolled up entirely and row 1 + " became blank. With the fix, only the output lines scroll and the buffer + " content remains visible near the top of the screen. + call assert_equal('A', g:system_term_row1) + + %bwipe! + delfunc s:CheckScroll + let &guioptions = save_guioptions +endfunc + func Test_gui_recursive_mapping() nmap ' nmap a :let didit = 1 diff --git a/src/version.c b/src/version.c index 7482aa8b71..bd95e9e3c4 100644 --- a/src/version.c +++ b/src/version.c @@ -734,6 +734,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 208, /**/ 207, /**/