comparison src/move.c @ 31577:3c21865e8068 v9.0.1121

patch 9.0.1121: cursor positioning and display problems with 'smoothscroll' Commit: https://github.com/vim/vim/commit/db4d88c2adfe8f8122341ac9d6cae27ef78451c8 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Dec 31 15:13:22 2022 +0000 patch 9.0.1121: cursor positioning and display problems with 'smoothscroll' Problem: Cursor positioning and display problems with 'smoothscroll' and using "zt", "zb" or "zz". Solution: Adjust computations and conditions. (Yee Cheng Chin, closes #11764)
author Bram Moolenaar <Bram@vim.org>
date Sat, 31 Dec 2022 16:15:03 +0100
parents 0c0b78aa7ae3
children 238ca27dbfd2
comparison
equal deleted inserted replaced
31576:1ae87829a0dc 31577:3c21865e8068
217 // account for it. See wlv_screen_line(). 217 // account for it. See wlv_screen_line().
218 if (*get_showbreak_value(curwin) != NUL) 218 if (*get_showbreak_value(curwin) != NUL)
219 return 0; 219 return 0;
220 #endif 220 #endif
221 return extra2 > 3 ? 0 : 3 - extra2; 221 return extra2 > 3 ? 0 : 3 - extra2;
222 }
223
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;
222 } 239 }
223 240
224 /* 241 /*
225 * Set curwin->s_skipcol to zero and redraw later if needed. 242 * Set curwin->s_skipcol to zero and redraw later if needed.
226 */ 243 */
2147 * a (wrapped) text line. Uses and sets "lp->fill". 2164 * a (wrapped) text line. Uses and sets "lp->fill".
2148 * Returns the height of the added line in "lp->height". 2165 * Returns the height of the added line in "lp->height".
2149 * Lines above the first one are incredibly high: MAXCOL. 2166 * Lines above the first one are incredibly high: MAXCOL.
2150 */ 2167 */
2151 static void 2168 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
2153 { 2172 {
2154 #ifdef FEAT_DIFF 2173 #ifdef FEAT_DIFF
2155 if (lp->fill < diff_check_fill(curwin, lp->lnum)) 2174 if (lp->fill < diff_check_fill(curwin, lp->lnum))
2156 { 2175 {
2157 // Add a filler line. 2176 // Add a filler line.
2172 if (hasFolding(lp->lnum, &lp->lnum, NULL)) 2191 if (hasFolding(lp->lnum, &lp->lnum, NULL))
2173 // Add a closed fold 2192 // Add a closed fold
2174 lp->height = 1; 2193 lp->height = 1;
2175 else 2194 else
2176 #endif 2195 #endif
2177 lp->height = PLINES_NOFILL(lp->lnum); 2196 lp->height = PLINES_WIN_NOFILL(curwin, lp->lnum, winheight);
2178 } 2197 }
2179 } 2198 }
2199
2200 static void
2201 topline_back(lineoff_T *lp)
2202 {
2203 topline_back_winheight(lp, TRUE);
2204 }
2205
2180 2206
2181 /* 2207 /*
2182 * Add one line below "lp->lnum". This can be a filler line, a closed fold or 2208 * Add one line below "lp->lnum". This can be a filler line, a closed fold or
2183 * a (wrapped) text line. Uses and sets "lp->fill". 2209 * a (wrapped) text line. Uses and sets "lp->fill".
2184 * Returns the height of the added line in "lp->height". 2210 * Returns the height of the added line in "lp->height".
2315 // count one logical line for a sequence of folded lines 2341 // count one logical line for a sequence of folded lines
2316 i = 1; 2342 i = 1;
2317 else 2343 else
2318 #endif 2344 #endif
2319 i = PLINES_NOFILL(top); 2345 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
2320 used += i; 2354 used += i;
2321 if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) 2355 if (extra + i <= off && bot < curbuf->b_ml.ml_line_count)
2322 { 2356 {
2323 #ifdef FEAT_FOLDING 2357 #ifdef FEAT_FOLDING
2324 if (hasFolding(bot, NULL, &bot)) 2358 if (hasFolding(bot, NULL, &bot))
2327 else 2361 else
2328 #endif 2362 #endif
2329 used += plines(bot); 2363 used += plines(bot);
2330 } 2364 }
2331 if (used > curwin->w_height) 2365 if (used > curwin->w_height)
2332 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; 2366 break;
2342 2367
2343 extra += i; 2368 extra += i;
2344 new_topline = top; 2369 new_topline = top;
2345 --top; 2370 --top;
2434 int min_scrolled = 1; 2459 int min_scrolled = 1;
2435 int extra = 0; 2460 int extra = 0;
2436 int i; 2461 int i;
2437 linenr_T line_count; 2462 linenr_T line_count;
2438 linenr_T old_topline = curwin->w_topline; 2463 linenr_T old_topline = curwin->w_topline;
2464 int old_skipcol = curwin->w_skipcol;
2439 lineoff_T loff; 2465 lineoff_T loff;
2440 lineoff_T boff; 2466 lineoff_T boff;
2441 #ifdef FEAT_DIFF 2467 #ifdef FEAT_DIFF
2442 int old_topfill = curwin->w_topfill; 2468 int old_topfill = curwin->w_topfill;
2443 int fill_below_window; 2469 int fill_below_window;
2449 long so = get_scrolloff_value(); 2475 long so = get_scrolloff_value();
2450 2476
2451 cln = curwin->w_cursor.lnum; 2477 cln = curwin->w_cursor.lnum;
2452 if (set_topbot) 2478 if (set_topbot)
2453 { 2479 {
2480 int set_skipcol = FALSE;
2481
2454 used = 0; 2482 used = 0;
2455 curwin->w_botline = cln + 1; 2483 curwin->w_botline = cln + 1;
2456 #ifdef FEAT_DIFF 2484 #ifdef FEAT_DIFF
2457 loff.fill = 0; 2485 loff.fill = 0;
2458 #endif 2486 #endif
2459 for (curwin->w_topline = curwin->w_botline; 2487 for (curwin->w_topline = curwin->w_botline;
2460 curwin->w_topline > 1; 2488 curwin->w_topline > 1;
2461 curwin->w_topline = loff.lnum) 2489 curwin->w_topline = loff.lnum)
2462 { 2490 {
2463 loff.lnum = curwin->w_topline; 2491 loff.lnum = curwin->w_topline;
2464 topline_back(&loff); 2492 topline_back_winheight(&loff, FALSE);
2465 if (loff.height == MAXCOL || used + loff.height > curwin->w_height) 2493 if (loff.height == MAXCOL)
2466 break; 2494 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 }
2467 used += loff.height; 2518 used += loff.height;
2468 #ifdef FEAT_DIFF 2519 #ifdef FEAT_DIFF
2469 curwin->w_topfill = loff.fill; 2520 curwin->w_topfill = loff.fill;
2470 #endif 2521 #endif
2471 } 2522 }
2473 curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; 2524 curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
2474 if (curwin->w_topline != old_topline 2525 if (curwin->w_topline != old_topline
2475 #ifdef FEAT_DIFF 2526 #ifdef FEAT_DIFF
2476 || curwin->w_topfill != old_topfill 2527 || curwin->w_topfill != old_topfill
2477 #endif 2528 #endif
2478 ) 2529 || set_skipcol
2530 || curwin->w_skipcol != 0)
2531 {
2479 curwin->w_valid &= ~(VALID_WROW|VALID_CROW); 2532 curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
2533 if (set_skipcol)
2534 redraw_later(UPD_NOT_VALID);
2535 else
2536 reset_skipcol();
2537 }
2480 } 2538 }
2481 else 2539 else
2482 validate_botline(); 2540 validate_botline();
2483 2541
2484 // The lines of the cursor line itself are always used. 2542 // The lines of the cursor line itself are always used.
2678 /* 2736 /*
2679 * If topline didn't change we need to restore w_botline and w_empty_rows 2737 * If topline didn't change we need to restore w_botline and w_empty_rows
2680 * (we changed them). 2738 * (we changed them).
2681 * If topline did change, update_screen() will set botline. 2739 * If topline did change, update_screen() will set botline.
2682 */ 2740 */
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)
2684 { 2744 {
2685 curwin->w_botline = old_botline; 2745 curwin->w_botline = old_botline;
2686 curwin->w_empty_rows = old_empty_rows; 2746 curwin->w_empty_rows = old_empty_rows;
2687 curwin->w_valid = old_valid; 2747 curwin->w_valid = old_valid;
2688 } 2748 }
2696 void 2756 void
2697 scroll_cursor_halfway(int atend) 2757 scroll_cursor_halfway(int atend)
2698 { 2758 {
2699 int above = 0; 2759 int above = 0;
2700 linenr_T topline; 2760 linenr_T topline;
2761 colnr_T skipcol = 0;
2762 int set_skipcol = FALSE;
2701 #ifdef FEAT_DIFF 2763 #ifdef FEAT_DIFF
2702 int topfill = 0; 2764 int topfill = 0;
2703 #endif 2765 #endif
2704 int below = 0; 2766 int below = 0;
2705 int used; 2767 int used;
2723 boff.fill = 0; 2785 boff.fill = 0;
2724 #else 2786 #else
2725 used = plines(loff.lnum); 2787 used = plines(loff.lnum);
2726 #endif 2788 #endif
2727 topline = loff.lnum; 2789 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
2728 while (topline > 1) 2801 while (topline > 1)
2729 { 2802 {
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
2730 if (below <= above) // add a line below the cursor first 2841 if (below <= above) // add a line below the cursor first
2731 { 2842 {
2732 if (boff.lnum < curbuf->b_ml.ml_line_count) 2843 if (boff.lnum < curbuf->b_ml.ml_line_count)
2733 { 2844 {
2734 botline_forw(&boff); 2845 botline_forw(&boff);
2762 } 2873 }
2763 } 2874 }
2764 #ifdef FEAT_FOLDING 2875 #ifdef FEAT_FOLDING
2765 if (!hasFolding(topline, &curwin->w_topline, NULL)) 2876 if (!hasFolding(topline, &curwin->w_topline, NULL))
2766 #endif 2877 #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 }
2768 #ifdef FEAT_DIFF 2893 #ifdef FEAT_DIFF
2769 curwin->w_topfill = topfill; 2894 curwin->w_topfill = topfill;
2770 if (old_topline > curwin->w_topline + curwin->w_height) 2895 if (old_topline > curwin->w_topline + curwin->w_height)
2771 curwin->w_botfill = FALSE; 2896 curwin->w_botfill = FALSE;
2772 check_topfill(curwin, FALSE); 2897 check_topfill(curwin, FALSE);