patch 9.2.0896: scroll: 'smoothscroll' position is lost when splitting a window
Commit:
https://github.com/vim/vim/commit/bd2970b041871bea99626c5ef701ae02216bc8c3
Author: Hirohito Higashi <
h.eas...@gmail.com>
Date: Sun Aug 2 17:25:35 2026 +0000
patch 9.2.0896: scroll: 'smoothscroll' position is lost when splitting a window
Problem: With 'smoothscroll' the position in a long line is lost when a
window is split and closed again.
Solution: With 'splitkeep' "screen" keep the skipped columns, they are part
of keeping the same screen lines. Otherwise put the cursor in the
row that keeps its relative position, instead of the last row.
closes: #20912
Co-Authored-By: Claude Opus 5 (1M context) <
nor...@anthropic.com>
Signed-off-by: Hirohito Higashi <
h.eas...@gmail.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 3b2f65a9c..a277a260f 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1,4 +1,4 @@
-*todo.txt* For Vim version 9.2. Last change: 2026 Aug 01
+*todo.txt* For Vim version 9.2. Last change: 2026 Aug 02
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41,9 +41,6 @@ squeezed to a couple of lines, for example ":help" followed by ":close". In
restore_snapshot_rec() restore more values from the snapshot, instead of
calling frame_new_height() and frame_new_width(), especially w_skipcol.
-With 'splitkeep' "screen" the scroll position is lost when splitting and
-closing a window, win_fix_cursor() moves the cursor to another line.
-
When a help item can't be found, then open 'helpfile'. Search for the tag in
that file and gtive E149 only when not found. Helps for a tiny Vim installed
without all the help files.
diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim
index f3aa38dc4..dc670fa7c 100644
--- a/src/testdir/test_window_cmd.vim
+++ b/src/testdir/test_window_cmd.vim
@@ -2034,6 +2034,25 @@ func Test_splitkeep_cmdheight()
set splitkeep& cmdheight&
endfunc
+func Test_splitkeep_screen_smoothscroll()
+ set splitkeep=screen
+ setlocal smoothscroll
+ call setline(1, [repeat('x', 3000)] + repeat(['line'], 10))
+ exe "normal! gg10\<C-E>"
+ redraw
+ let skipcol = winsaveview().skipcol
+ call assert_notequal(0, skipcol)
+
+ " Keeping the same screen lines also keeps the position in a long line.
+ split
+ close
+ redraw
+ call assert_equal(skipcol, winsaveview().skipcol)
+
+ %bwipeout!
+ set splitkeep&
+endfunc
+
func Test_aucmd_win_scroll_multibyte()
" Using the autocommand window must not scroll the current window when the
" cursor is behind multi-byte characters.
diff --git a/src/window.c b/src/window.c
index 04d3d86c4..8ac5b8f5e 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7287,6 +7287,9 @@ win_fix_scroll(int resize)
int diff = (wp->w_winrow - wp->w_prev_winrow)
+ (wp->w_height - wp->w_prev_height);
pos_T cursor = wp->w_cursor;
+ linenr_T topline = wp->w_topline;
+ colnr_T skipcol = wp->w_skipcol;
+
wp->w_cursor.lnum = wp->w_botline - 1;
// Add difference in height and row to botline.
@@ -7301,6 +7304,9 @@ win_fix_scroll(int resize)
scroll_to_fraction(wp, wp->w_prev_height);
wp->w_cursor = cursor;
+ // Keeping the same screen lines includes the skipped columns.
+ if (wp->w_topline == topline)
+ wp->w_skipcol = skipcol;
wp->w_valid &= ~VALID_WCOL;
}
else if (wp == curwin)
@@ -7468,15 +7474,17 @@ scroll_to_fraction(win_T *wp, int prev_height)
* Make cursor line the first line in the window. If not enough
* room use w_skipcol;
*/
+ int want_row = wp->w_wrow; // where the cursor should be
+
wp->w_wrow = line_size;
if (wp->w_wrow >= wp->w_height
&& (wp->w_width - win_col_off(wp)) > 0)
{
- // The cursor must be visible, override the scroll position.
+ // Skip columns to get the cursor in the wanted row.
colnr_T skipcol = wp->w_width - win_col_off(wp);
--wp->w_wrow;
- while (wp->w_wrow >= wp->w_height)
+ while (wp->w_wrow > want_row)
{
skipcol += wp->w_width - win_col_off(wp) + win_col_off2(wp);
--wp->w_wrow;