From 86bbe41459af3ea6bc0b62501cf5de6335234ae8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 1 Aug 2026 08:28:59 +0800 Subject: [PATCH] vim-patch:9.2.0885: scroll: 'smoothscroll' position is lost when the window is squeezed Problem: With 'smoothscroll' the scroll position in a long line is lost when a window is temporarily squeezed to a couple of lines, for example when opening and closing a help window. Solution: When the cursor ends up in the skipped columns, skip up to the screen line the cursor is in instead of showing the start of the line. closes: vim/vim#20892 https://github.com/vim/vim/commit/15f8ba5cec35feea22622fbc7c78f3204aad50df Co-authored-by: Hirohito Higashi Co-Authored-By: Claude Opus 5 (1M context) --- src/nvim/move.c | 16 +++++++++++++--- test/old/testdir/test_scroll_opt.vim | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/nvim/move.c b/src/nvim/move.c index 767c473eca..3e3e427b16 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -1896,9 +1896,19 @@ void scroll_cursor_top(win_T *wp, int min_scroll, int always) } else if (wp->w_topline == wp->w_cursor.lnum) { validate_virtcol(wp); if (wp->w_skipcol >= wp->w_virtcol) { - // TODO(vim): if the line doesn't fit may optimize w_skipcol instead - // of making it zero - reset_skipcol(wp); + // Skip up to the screen line the cursor is in, so that the + // position in the line is kept. + int width1 = wp->w_width - win_col_off(wp); + int width2 = width1 + win_col_off2(wp); + int plines_off = 0; + if (width2 > 0 && wp->w_virtcol >= width1) { + plines_off = (wp->w_virtcol - width1) / width2 + 1; + } + int skipcol = skipcol_from_plines(wp, plines_off); + if (skipcol != wp->w_skipcol) { + wp->w_skipcol = skipcol; + redraw_later(wp, UPD_SOME_VALID); + } } } if (wp->w_topline != old_topline diff --git a/test/old/testdir/test_scroll_opt.vim b/test/old/testdir/test_scroll_opt.vim index f15c5a0ec4..43a73eb8ce 100644 --- a/test/old/testdir/test_scroll_opt.vim +++ b/test/old/testdir/test_scroll_opt.vim @@ -1353,6 +1353,27 @@ func Test_smoothscroll_cursor_back_in_line() bwipe! endfunc +func Test_smoothscroll_squeezed_window() + setlocal smoothscroll + call setline(1, [repeat('x', 3000)] + repeat(['line'], 10)) + exe "norm! gg10\" + redraw + let skipcol = winsaveview().skipcol + call assert_notequal(0, skipcol) + let virtcol = virtcol('.') + + " Squeezing the window to one line and restoring it must not scroll back to + " the start of the line. + new + wincmd _ + close + redraw + call assert_notequal(0, winsaveview().skipcol) + call assert_equal(virtcol, virtcol('.')) + + bwipe! +endfunc + func Test_smoothscroll_long_line_zb() call NewWindow(10, 40) call setline(1, 'abcde '->repeat(150))