@@ -221,6 +221,23 @@ smoothscroll_marker_overlap(int extra2)
221221 return extra2 > 3 ? 0 : 3 - extra2 ;
222222}
223223
224+ /*
225+ * Calculates the skipcol offset for window "wp" given how many
226+ * physical lines we want to scroll down.
227+ */
228+ static int
229+ skipcol_from_plines (win_T * wp , int plines_off )
230+ {
231+ int width1 = wp -> w_width - win_col_off (wp );
232+
233+ int skipcol = 0 ;
234+ if (plines_off > 0 )
235+ skipcol += width1 ;
236+ if (plines_off > 1 )
237+ skipcol += (width1 + win_col_off2 (wp )) * (plines_off - 1 );
238+ return skipcol ;
239+ }
240+
224241/*
225242 * Set curwin->s_skipcol to zero and redraw later if needed.
226243 */
@@ -2149,7 +2166,9 @@ scrollup_clamp(void)
21492166 * Lines above the first one are incredibly high: MAXCOL.
21502167 */
21512168 static void
2152- topline_back (lineoff_T * lp )
2169+ topline_back_winheight (
2170+ lineoff_T * lp ,
2171+ int winheight ) // when TRUE limit to window height
21532172{
21542173#ifdef FEAT_DIFF
21552174 if (lp -> fill < diff_check_fill (curwin , lp -> lnum ))
@@ -2174,10 +2193,17 @@ topline_back(lineoff_T *lp)
21742193 lp -> height = 1 ;
21752194 else
21762195#endif
2177- lp -> height = PLINES_NOFILL ( lp -> lnum );
2196+ lp -> height = PLINES_WIN_NOFILL ( curwin , lp -> lnum , winheight );
21782197 }
21792198}
21802199
2200+ static void
2201+ topline_back (lineoff_T * lp )
2202+ {
2203+ topline_back_winheight (lp , TRUE);
2204+ }
2205+
2206+
21812207/*
21822208 * Add one line below "lp->lnum". This can be a filler line, a closed fold or
21832209 * a (wrapped) text line. Uses and sets "lp->fill".
@@ -2317,6 +2343,14 @@ scroll_cursor_top(int min_scroll, int always)
23172343 else
23182344#endif
23192345 i = PLINES_NOFILL (top );
2346+ if (top < curwin -> w_topline )
2347+ scrolled += i ;
2348+
2349+ // If scrolling is needed, scroll at least 'sj' lines.
2350+ if ((new_topline >= curwin -> w_topline || scrolled > min_scroll )
2351+ && extra >= off )
2352+ break ;
2353+
23202354 used += i ;
23212355 if (extra + i <= off && bot < curbuf -> b_ml .ml_line_count )
23222356 {
@@ -2330,15 +2364,6 @@ scroll_cursor_top(int min_scroll, int always)
23302364 }
23312365 if (used > curwin -> w_height )
23322366 break ;
2333- if (top < curwin -> w_topline )
2334- scrolled += i ;
2335-
2336- /*
2337- * If scrolling is needed, scroll at least 'sj' lines.
2338- */
2339- if ((new_topline >= curwin -> w_topline || scrolled > min_scroll )
2340- && extra >= off )
2341- break ;
23422367
23432368 extra += i ;
23442369 new_topline = top ;
@@ -2436,6 +2461,7 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
24362461 int i ;
24372462 linenr_T line_count ;
24382463 linenr_T old_topline = curwin -> w_topline ;
2464+ int old_skipcol = curwin -> w_skipcol ;
24392465 lineoff_T loff ;
24402466 lineoff_T boff ;
24412467#ifdef FEAT_DIFF
@@ -2451,6 +2477,8 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
24512477 cln = curwin -> w_cursor .lnum ;
24522478 if (set_topbot )
24532479 {
2480+ int set_skipcol = FALSE;
2481+
24542482 used = 0 ;
24552483 curwin -> w_botline = cln + 1 ;
24562484#ifdef FEAT_DIFF
@@ -2461,9 +2489,32 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
24612489 curwin -> w_topline = loff .lnum )
24622490 {
24632491 loff .lnum = curwin -> w_topline ;
2464- topline_back (& loff );
2465- if (loff .height == MAXCOL || used + loff . height > curwin -> w_height )
2492+ topline_back_winheight (& loff , FALSE );
2493+ if (loff .height == MAXCOL )
24662494 break ;
2495+ if (used + loff .height > curwin -> w_height )
2496+ {
2497+ if (curwin -> w_p_sms && curwin -> w_p_wrap )
2498+ {
2499+ // 'smoothscroll' and 'wrap' are set. The above line is
2500+ // too long to show in its entirety, so we show just a part
2501+ // of it.
2502+ if (used < curwin -> w_height )
2503+ {
2504+ int plines_offset = used + loff .height
2505+ - curwin -> w_height ;
2506+ used = curwin -> w_height ;
2507+ #ifdef FEAT_DIFF
2508+ curwin -> w_topfill = loff .fill ;
2509+ #endif
2510+ curwin -> w_topline = loff .lnum ;
2511+ curwin -> w_skipcol = skipcol_from_plines (
2512+ curwin , plines_offset );
2513+ set_skipcol = TRUE;
2514+ }
2515+ }
2516+ break ;
2517+ }
24672518 used += loff .height ;
24682519#ifdef FEAT_DIFF
24692520 curwin -> w_topfill = loff .fill ;
@@ -2475,8 +2526,15 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
24752526#ifdef FEAT_DIFF
24762527 || curwin -> w_topfill != old_topfill
24772528#endif
2478- )
2529+ || set_skipcol
2530+ || curwin -> w_skipcol != 0 )
2531+ {
24792532 curwin -> w_valid &= ~(VALID_WROW |VALID_CROW );
2533+ if (set_skipcol )
2534+ redraw_later (UPD_NOT_VALID );
2535+ else
2536+ reset_skipcol ();
2537+ }
24802538 }
24812539 else
24822540 validate_botline ();
@@ -2680,7 +2738,9 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
26802738 * (we changed them).
26812739 * If topline did change, update_screen() will set botline.
26822740 */
2683- if (curwin -> w_topline == old_topline && set_topbot )
2741+ if (curwin -> w_topline == old_topline
2742+ && curwin -> w_skipcol == old_skipcol
2743+ && set_topbot )
26842744 {
26852745 curwin -> w_botline = old_botline ;
26862746 curwin -> w_empty_rows = old_empty_rows ;
@@ -2698,6 +2758,8 @@ scroll_cursor_halfway(int atend)
26982758{
26992759 int above = 0 ;
27002760 linenr_T topline ;
2761+ colnr_T skipcol = 0 ;
2762+ int set_skipcol = FALSE;
27012763#ifdef FEAT_DIFF
27022764 int topfill = 0 ;
27032765#endif
@@ -2725,8 +2787,57 @@ scroll_cursor_halfway(int atend)
27252787 used = plines (loff .lnum );
27262788#endif
27272789 topline = loff .lnum ;
2790+
2791+ int half_height = 0 ;
2792+ int smooth_scroll = FALSE;
2793+ if (curwin -> w_p_sms && curwin -> w_p_wrap )
2794+ {
2795+ // 'smoothscroll' and 'wrap' are set
2796+ smooth_scroll = TRUE;
2797+ half_height = (curwin -> w_height - used ) / 2 ;
2798+ used = 0 ;
2799+ }
2800+
27282801 while (topline > 1 )
27292802 {
2803+ // If using smoothscroll, we can precisely scroll to the
2804+ // exact point where the cursor is halfway down the screen.
2805+ if (smooth_scroll )
2806+ {
2807+ topline_back_winheight (& loff , FALSE);
2808+ if (loff .height == MAXCOL )
2809+ break ;
2810+ else
2811+ used += loff .height ;
2812+ if (used > half_height )
2813+ {
2814+ if (used - loff .height < half_height )
2815+ {
2816+ int plines_offset = used - half_height ;
2817+ loff .height -= plines_offset ;
2818+ used = half_height ;
2819+
2820+ topline = loff .lnum ;
2821+ #ifdef FEAT_DIFF
2822+ topfill = loff .fill ;
2823+ #endif
2824+ skipcol = skipcol_from_plines (curwin , plines_offset );
2825+ set_skipcol = TRUE;
2826+ }
2827+ break ;
2828+ }
2829+ topline = loff .lnum ;
2830+ #ifdef FEAT_DIFF
2831+ topfill = loff .fill ;
2832+ #endif
2833+ continue ;
2834+ }
2835+
2836+ // If not using smoothscroll, we have to iteratively find how many
2837+ // lines to scroll down to roughly fit the cursor.
2838+ // This may not be right in the middle if the lines' physical height >
2839+ // 1 (e.g. 'wrap' is on).
2840+
27302841 if (below <= above ) // add a line below the cursor first
27312842 {
27322843 if (boff .lnum < curbuf -> b_ml .ml_line_count )
@@ -2764,7 +2875,21 @@ scroll_cursor_halfway(int atend)
27642875#ifdef FEAT_FOLDING
27652876 if (!hasFolding (topline , & curwin -> w_topline , NULL ))
27662877#endif
2767- curwin -> w_topline = topline ;
2878+ {
2879+ if (curwin -> w_topline != topline
2880+ || set_skipcol
2881+ || curwin -> w_skipcol != 0 )
2882+ {
2883+ curwin -> w_topline = topline ;
2884+ if (set_skipcol )
2885+ {
2886+ curwin -> w_skipcol = skipcol ;
2887+ redraw_later (UPD_NOT_VALID );
2888+ }
2889+ else
2890+ reset_skipcol ();
2891+ }
2892+ }
27682893#ifdef FEAT_DIFF
27692894 curwin -> w_topfill = topfill ;
27702895 if (old_topline > curwin -> w_topline + curwin -> w_height )
0 commit comments