diff src/move.c @ 30610:6c6ac189a05f v9.0.0640

patch 9.0.0640: cannot scroll by screen line if a line wraps Commit: https://github.com/vim/vim/commit/f6196f424474e2a9c160f2a995fc2691f82b58f9 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Oct 2 21:29:55 2022 +0100 patch 9.0.0640: cannot scroll by screen line if a line wraps Problem: Cannot scroll by screen line if a line wraps. Solution: Add the 'smoothscroll' option. Only works for CTRL-E and CTRL-Y so far.
author Bram Moolenaar <Bram@vim.org>
date Sun, 02 Oct 2022 22:30:15 +0200
parents 729e2305f4b2
children 70d6345a2976
line wrap: on
line diff
--- a/src/move.c
+++ b/src/move.c
@@ -36,6 +36,32 @@ static void topline_back(lineoff_T *lp);
 static void botline_forw(lineoff_T *lp);
 
 /*
+ * Reduce "n" for the screen lines skipped with "wp->w_skipcol".
+ */
+    static int
+adjust_plines_for_skipcol(win_T *wp, int n)
+{
+    if (wp->w_skipcol == 0)
+	return n;
+
+    int off = 0;
+    int width = wp->w_width - win_col_off(wp);
+    if (wp->w_skipcol >= width)
+    {
+	++off;
+	int skip = wp->w_skipcol - width;
+	width -= win_col_off2(wp);
+	while (skip >= width)
+	{
+	    ++off;
+	    skip -= width;
+	}
+    }
+    wp->w_valid &= ~VALID_WROW;
+    return n - off;
+}
+
+/*
  * Compute wp->w_botline for the current wp->w_topline.  Can be called after
  * wp->w_topline changed.
  */
@@ -78,12 +104,16 @@ comp_botline(win_T *wp)
 	}
 	else
 #endif
+	{
 #ifdef FEAT_DIFF
 	    if (lnum == wp->w_topline)
 		n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill;
 	    else
 #endif
 		n = plines_win(wp, lnum, TRUE);
+	    if (lnum == wp->w_topline)
+		n = adjust_plines_for_skipcol(wp, n);
+	}
 	if (
 #ifdef FEAT_FOLDING
 		lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum
@@ -778,13 +808,18 @@ curs_rows(win_T *wp)
 	    }
 	    else
 #endif
+	    {
+		int n;
 #ifdef FEAT_DIFF
 		if (lnum == wp->w_topline)
-		    wp->w_cline_row += plines_win_nofill(wp, lnum++, TRUE)
-							      + wp->w_topfill;
+		    n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill;
 		else
 #endif
-		    wp->w_cline_row += plines_win(wp, lnum++, TRUE);
+		    n = plines_win(wp, lnum, TRUE);
+		if (lnum++ == wp->w_topline)
+		    n = adjust_plines_for_skipcol(wp, n);
+		wp->w_cline_row += n;
+	    }
 	}
     }
 
@@ -1237,7 +1272,7 @@ curs_columns(
 	else if (extra < 0)
 	    win_del_lines(curwin, 0, -extra, FALSE, FALSE, 0);
     }
-    else
+    else if (!curwin->w_p_sms)
 	curwin->w_skipcol = 0;
     if (prev_skipcol != curwin->w_skipcol)
 	redraw_later(UPD_NOT_VALID);
@@ -1422,6 +1457,14 @@ scrolldown(
     long	done = 0;	// total # of physical lines done
     int		wrow;
     int		moved = FALSE;
+    int		width1 = 0;
+    int		width2 = 0;
+
+    if (curwin->w_p_wrap && curwin->w_p_sms)
+    {
+	width1 = curwin->w_width - curwin_col_off();
+	width2 = width1 - curwin_col_off2();
+    }
 
 #ifdef FEAT_FOLDING
     linenr_T	first;
@@ -1442,25 +1485,57 @@ scrolldown(
 	else
 #endif
 	{
-	    if (curwin->w_topline == 1)
+	    if (curwin->w_topline == 1 && curwin->w_skipcol < width1)
 		break;
-	    --curwin->w_topline;
+	    if (curwin->w_p_wrap && curwin->w_p_sms
+						  && curwin->w_skipcol >= width1)
+	    {
+		if (curwin->w_skipcol >= width1 + width2)
+		    curwin->w_skipcol -= width2;
+		else
+		    curwin->w_skipcol -= width1;
+		redraw_later(UPD_NOT_VALID);
+		++done;
+	    }
+	    else
+	    {
+		--curwin->w_topline;
+		curwin->w_skipcol = 0;
 #ifdef FEAT_DIFF
-	    curwin->w_topfill = 0;
+		curwin->w_topfill = 0;
 #endif
 #ifdef FEAT_FOLDING
-	    // A sequence of folded lines only counts for one logical line
-	    if (hasFolding(curwin->w_topline, &first, NULL))
-	    {
-		++done;
-		if (!byfold)
-		    line_count -= curwin->w_topline - first - 1;
-		curwin->w_botline -= curwin->w_topline - first;
-		curwin->w_topline = first;
+		// A sequence of folded lines only counts for one logical line
+		if (hasFolding(curwin->w_topline, &first, NULL))
+		{
+		    ++done;
+		    if (!byfold)
+			line_count -= curwin->w_topline - first - 1;
+		    curwin->w_botline -= curwin->w_topline - first;
+		    curwin->w_topline = first;
+		}
+		else
+#endif
+		if (curwin->w_p_wrap && curwin->w_p_sms)
+		{
+		    int size = win_linetabsize(curwin, curwin->w_topline,
+				   ml_get(curwin->w_topline), (colnr_T)MAXCOL);
+		    if (size > width1)
+		    {
+			curwin->w_skipcol = width1;
+			size -= width1;
+			redraw_later(UPD_NOT_VALID);
+		    }
+		    while (size > width2)
+		    {
+			curwin->w_skipcol += width2;
+			size -= width2;
+		    }
+		    ++done;
+		}
+		else
+		    done += PLINES_NOFILL(curwin->w_topline);
 	    }
-	    else
-#endif
-		done += PLINES_NOFILL(curwin->w_topline);
 	}
 	--curwin->w_botline;		// approximate w_botline
 	invalidate_botline();
@@ -1565,6 +1640,41 @@ scrollup(
     }
     else
 #endif
+    if (curwin->w_p_wrap && curwin->w_p_sms)
+    {
+	int off1 = curwin_col_off();
+	int off2 = off1 + curwin_col_off2();
+	int add;
+	int size = win_linetabsize(curwin, curwin->w_topline,
+				   ml_get(curwin->w_topline), (colnr_T)MAXCOL);
+	linenr_T prev_topline = curwin->w_topline;
+
+	// 'smoothscroll': increase "w_skipcol" until it goes over the end of
+	// the line, then advance to the next line.
+	for (int todo = line_count; todo > 0; --todo)
+	{
+	    add = curwin->w_width - (curwin->w_skipcol > 0 ? off2 : off1);
+	    curwin->w_skipcol += add;
+	    if (curwin->w_skipcol >= size)
+	    {
+		if (curwin->w_topline == curbuf->b_ml.ml_line_count)
+		{
+		    curwin->w_skipcol -= add;
+		    break;
+		}
+		++curwin->w_topline;
+		++curwin->w_botline;	// approximate w_botline
+		curwin->w_skipcol = 0;
+		if (todo > 1)
+		    size = win_linetabsize(curwin, curwin->w_topline,
+				   ml_get(curwin->w_topline), (colnr_T)MAXCOL);
+	    }
+	}
+	if (curwin->w_topline == prev_topline)
+	    // need to redraw even though w_topline didn't change
+	    redraw_later(UPD_NOT_VALID);
+    }
+    else
     {
 	curwin->w_topline += line_count;
 	curwin->w_botline += line_count;	// approximate w_botline