patch 9.2.0208: MS-Windows: excessive scroll-behaviour with go+=!

Problem:  MS-Windows: excessive scroll-behaviour with go+=! after
          switching to ConPTY as default (after v9.2.0048).
Solution: Use tl_cursor_pos to determine the number of lines to scroll
          (Yasuhiro Matsumoto).

Since patch 9.2.0048 (71cc1b12) made ConPTY the default on Windows 11,
running :!cmd with guioptions+=! scrolls up the entire window height
instead of only the output lines.

ConPTY damages all terminal rows on initialization even when they are
empty, which causes tl_dirty_row_end to equal Rows.  The scroll-up loop
in update_system_term() then scrolls the full screen because
(Rows - tl_toprow) < tl_dirty_row_end is always true until tl_toprow
reaches 0.

Use the cursor position instead of tl_dirty_row_end for the scroll
calculation, since it reflects where actual content has been written.

The scroll bug only occurs with ConPTY.  With winpty the terminal
finishes too quickly for the timer-based screen check to work.

closes: #19735

Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yasuhiro Matsumoto
2026-03-19 21:48:57 +00:00
committed by Christian Brabandt
parent 6391a38e5e
commit 67ae763557
3 changed files with 47 additions and 1 deletions
+4 -1
View File
@@ -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;
+41
View File
@@ -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 ' <C-W>
nmap <C-W>a :let didit = 1<CR>
+2
View File
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
208,
/**/
207,
/**/