To: vim_dev@googlegroups.com Subject: Patch 9.0.1121 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1121 Problem: Cursor positioning and display problems with 'smoothscroll' and using "zt", "zb" or "zz". Solution: Adjust computations and conditions. (Yee Cheng Chin, closes #11764) Files: src/macros.h, src/move.c, src/testdir/test_scroll_opt.vim, src/testdir/dumps/Test_smooth_long_10.dump, src/testdir/dumps/Test_smooth_long_11.dump, src/testdir/dumps/Test_smooth_long_12.dump, src/testdir/dumps/Test_smooth_long_13.dump, src/testdir/dumps/Test_smooth_long_14.dump, src/testdir/dumps/Test_smooth_long_15.dump, src/testdir/dumps/Test_smooth_long_8.dump, src/testdir/dumps/Test_smooth_long_9.dump *** ../vim-9.0.1120/src/macros.h 2022-09-17 21:57:35.860822365 +0100 --- src/macros.h 2022-12-31 15:02:24.217129374 +0000 *************** *** 253,260 **** --- 253,262 ---- #ifdef FEAT_DIFF # define PLINES_NOFILL(x) plines_nofill(x) + # define PLINES_WIN_NOFILL(w, l, h) plines_win_nofill((w), (l), (h)) #else # define PLINES_NOFILL(x) plines(x) + # define PLINES_WIN_NOFILL(w, l, h) plines_win((w), (l), (h)) #endif #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_CLIENTSERVER) *** ../vim-9.0.1120/src/move.c 2022-12-18 12:28:54.330332513 +0000 --- src/move.c 2022-12-31 15:08:56.259795435 +0000 *************** *** 222,227 **** --- 222,244 ---- } /* + * Calculates the skipcol offset for window "wp" given how many + * physical lines we want to scroll down. + */ + static int + skipcol_from_plines(win_T *wp, int plines_off) + { + int width1 = wp->w_width - win_col_off(wp); + + int skipcol = 0; + if (plines_off > 0) + skipcol += width1; + if (plines_off > 1) + skipcol += (width1 + win_col_off2(wp)) * (plines_off - 1); + return skipcol; + } + + /* * Set curwin->s_skipcol to zero and redraw later if needed. */ static void *************** *** 2149,2155 **** * Lines above the first one are incredibly high: MAXCOL. */ static void ! topline_back(lineoff_T *lp) { #ifdef FEAT_DIFF if (lp->fill < diff_check_fill(curwin, lp->lnum)) --- 2166,2174 ---- * Lines above the first one are incredibly high: MAXCOL. */ static void ! topline_back_winheight( ! lineoff_T *lp, ! int winheight) // when TRUE limit to window height { #ifdef FEAT_DIFF if (lp->fill < diff_check_fill(curwin, lp->lnum)) *************** *** 2174,2183 **** lp->height = 1; else #endif ! lp->height = PLINES_NOFILL(lp->lnum); } } /* * Add one line below "lp->lnum". This can be a filler line, a closed fold or * a (wrapped) text line. Uses and sets "lp->fill". --- 2193,2209 ---- lp->height = 1; else #endif ! lp->height = PLINES_WIN_NOFILL(curwin, lp->lnum, winheight); } } + static void + topline_back(lineoff_T *lp) + { + topline_back_winheight(lp, TRUE); + } + + /* * Add one line below "lp->lnum". This can be a filler line, a closed fold or * a (wrapped) text line. Uses and sets "lp->fill". *************** *** 2317,2322 **** --- 2343,2356 ---- else #endif i = PLINES_NOFILL(top); + if (top < curwin->w_topline) + scrolled += i; + + // If scrolling is needed, scroll at least 'sj' lines. + if ((new_topline >= curwin->w_topline || scrolled > min_scroll) + && extra >= off) + break; + used += i; if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) { *************** *** 2330,2344 **** } if (used > curwin->w_height) break; - if (top < curwin->w_topline) - scrolled += i; - - /* - * If scrolling is needed, scroll at least 'sj' lines. - */ - if ((new_topline >= curwin->w_topline || scrolled > min_scroll) - && extra >= off) - break; extra += i; new_topline = top; --- 2364,2369 ---- *************** *** 2436,2441 **** --- 2461,2467 ---- int i; linenr_T line_count; linenr_T old_topline = curwin->w_topline; + int old_skipcol = curwin->w_skipcol; lineoff_T loff; lineoff_T boff; #ifdef FEAT_DIFF *************** *** 2451,2456 **** --- 2477,2484 ---- cln = curwin->w_cursor.lnum; if (set_topbot) { + int set_skipcol = FALSE; + used = 0; curwin->w_botline = cln + 1; #ifdef FEAT_DIFF *************** *** 2461,2469 **** curwin->w_topline = loff.lnum) { loff.lnum = curwin->w_topline; ! topline_back(&loff); ! if (loff.height == MAXCOL || used + loff.height > curwin->w_height) break; used += loff.height; #ifdef FEAT_DIFF curwin->w_topfill = loff.fill; --- 2489,2520 ---- curwin->w_topline = loff.lnum) { loff.lnum = curwin->w_topline; ! topline_back_winheight(&loff, FALSE); ! if (loff.height == MAXCOL) ! break; ! if (used + loff.height > curwin->w_height) ! { ! if (curwin->w_p_sms && curwin->w_p_wrap) ! { ! // 'smoothscroll' and 'wrap' are set. The above line is ! // too long to show in its entirety, so we show just a part ! // of it. ! if (used < curwin->w_height) ! { ! int plines_offset = used + loff.height ! - curwin->w_height; ! used = curwin->w_height; ! #ifdef FEAT_DIFF ! curwin->w_topfill = loff.fill; ! #endif ! curwin->w_topline = loff.lnum; ! curwin->w_skipcol = skipcol_from_plines( ! curwin, plines_offset); ! set_skipcol = TRUE; ! } ! } break; + } used += loff.height; #ifdef FEAT_DIFF curwin->w_topfill = loff.fill; *************** *** 2475,2482 **** #ifdef FEAT_DIFF || curwin->w_topfill != old_topfill #endif ! ) curwin->w_valid &= ~(VALID_WROW|VALID_CROW); } else validate_botline(); --- 2526,2540 ---- #ifdef FEAT_DIFF || curwin->w_topfill != old_topfill #endif ! || set_skipcol ! || curwin->w_skipcol != 0) ! { curwin->w_valid &= ~(VALID_WROW|VALID_CROW); + if (set_skipcol) + redraw_later(UPD_NOT_VALID); + else + reset_skipcol(); + } } else validate_botline(); *************** *** 2680,2686 **** * (we changed them). * If topline did change, update_screen() will set botline. */ ! if (curwin->w_topline == old_topline && set_topbot) { curwin->w_botline = old_botline; curwin->w_empty_rows = old_empty_rows; --- 2738,2746 ---- * (we changed them). * If topline did change, update_screen() will set botline. */ ! if (curwin->w_topline == old_topline ! && curwin->w_skipcol == old_skipcol ! && set_topbot) { curwin->w_botline = old_botline; curwin->w_empty_rows = old_empty_rows; *************** *** 2698,2703 **** --- 2758,2765 ---- { int above = 0; linenr_T topline; + colnr_T skipcol = 0; + int set_skipcol = FALSE; #ifdef FEAT_DIFF int topfill = 0; #endif *************** *** 2725,2732 **** --- 2787,2843 ---- used = plines(loff.lnum); #endif topline = loff.lnum; + + int half_height = 0; + int smooth_scroll = FALSE; + if (curwin->w_p_sms && curwin->w_p_wrap) + { + // 'smoothscroll' and 'wrap' are set + smooth_scroll = TRUE; + half_height = (curwin->w_height - used) / 2; + used = 0; + } + while (topline > 1) { + // If using smoothscroll, we can precisely scroll to the + // exact point where the cursor is halfway down the screen. + if (smooth_scroll) + { + topline_back_winheight(&loff, FALSE); + if (loff.height == MAXCOL) + break; + else + used += loff.height; + if (used > half_height) + { + if (used - loff.height < half_height) + { + int plines_offset = used - half_height; + loff.height -= plines_offset; + used = half_height; + + topline = loff.lnum; + #ifdef FEAT_DIFF + topfill = loff.fill; + #endif + skipcol = skipcol_from_plines(curwin, plines_offset); + set_skipcol = TRUE; + } + break; + } + topline = loff.lnum; + #ifdef FEAT_DIFF + topfill = loff.fill; + #endif + continue; + } + + // If not using smoothscroll, we have to iteratively find how many + // lines to scroll down to roughly fit the cursor. + // This may not be right in the middle if the lines' physical height > + // 1 (e.g. 'wrap' is on). + if (below <= above) // add a line below the cursor first { if (boff.lnum < curbuf->b_ml.ml_line_count) *************** *** 2764,2770 **** #ifdef FEAT_FOLDING if (!hasFolding(topline, &curwin->w_topline, NULL)) #endif ! curwin->w_topline = topline; #ifdef FEAT_DIFF curwin->w_topfill = topfill; if (old_topline > curwin->w_topline + curwin->w_height) --- 2875,2895 ---- #ifdef FEAT_FOLDING if (!hasFolding(topline, &curwin->w_topline, NULL)) #endif ! { ! if (curwin->w_topline != topline ! || set_skipcol ! || curwin->w_skipcol != 0) ! { ! curwin->w_topline = topline; ! if (set_skipcol) ! { ! curwin->w_skipcol = skipcol; ! redraw_later(UPD_NOT_VALID); ! } ! else ! reset_skipcol(); ! } ! } #ifdef FEAT_DIFF curwin->w_topfill = topfill; if (old_topline > curwin->w_topline + curwin->w_height) *** ../vim-9.0.1120/src/testdir/test_scroll_opt.vim 2022-12-03 18:35:04.244951282 +0000 --- src/testdir/test_scroll_opt.vim 2022-12-31 14:57:51.897227088 +0000 *************** *** 296,301 **** --- 296,309 ---- call term_sendkeys(buf, "0j") call VerifyScreenDump(buf, 'Test_smooth_long_10', {}) + " Test zt/zz/zb that they work properly when a long line is above it + call term_sendkeys(buf, "zb") + call VerifyScreenDump(buf, 'Test_smooth_long_11', {}) + call term_sendkeys(buf, "zz") + call VerifyScreenDump(buf, 'Test_smooth_long_12', {}) + call term_sendkeys(buf, "zt") + call VerifyScreenDump(buf, 'Test_smooth_long_13', {}) + " Repeat the step and move the cursor down again. " This time, use a shorter long line that is barely long enough to span more " than one window. Note that the cursor is at the bottom this time because *************** *** 303,309 **** call term_sendkeys(buf, ":call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(10)) .. ' end', 'four'])\") call term_sendkeys(buf, "3Gzt") call term_sendkeys(buf, "j") ! call VerifyScreenDump(buf, 'Test_smooth_long_11', {}) " Repeat the step but this time start it when the line is smooth-scrolled by " one line. This tests that the offset calculation is still correct and --- 311,317 ---- call term_sendkeys(buf, ":call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(10)) .. ' end', 'four'])\") call term_sendkeys(buf, "3Gzt") call term_sendkeys(buf, "j") ! call VerifyScreenDump(buf, 'Test_smooth_long_14', {}) " Repeat the step but this time start it when the line is smooth-scrolled by " one line. This tests that the offset calculation is still correct and *************** *** 311,317 **** " screen. call term_sendkeys(buf, "3Gzt") call term_sendkeys(buf, "\j") ! call VerifyScreenDump(buf, 'Test_smooth_long_12', {}) call StopVimInTerminal(buf) endfunc --- 319,325 ---- " screen. call term_sendkeys(buf, "3Gzt") call term_sendkeys(buf, "\j") ! call VerifyScreenDump(buf, 'Test_smooth_long_15', {}) call StopVimInTerminal(buf) endfunc *** ../vim-9.0.1120/src/testdir/dumps/Test_smooth_long_10.dump 2022-11-19 12:24:39.758174328 +0000 --- src/testdir/dumps/Test_smooth_long_10.dump 2022-12-31 14:57:51.897227088 +0000 *************** *** 1,6 **** ! >f+0&#ffffff0|o|u|r| @35 |~+0#4040ff13&| @38 |~| @38 - |~| @38 - |~| @38 |:+0#0000000&|s|e|t| |s|c|r|o|l@1|o| @9|4|,|1| @10|B|o|t| --- 1,6 ---- ! |<+0#4040ff13#ffffff0@2|o+0#0000000&|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o ! |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 ! >f|o|u|r| @35 |~+0#4040ff13&| @38 |~| @38 |:+0#0000000&|s|e|t| |s|c|r|o|l@1|o| @9|4|,|1| @10|B|o|t| *** ../vim-9.0.1120/src/testdir/dumps/Test_smooth_long_11.dump 2022-11-19 12:24:39.758174328 +0000 --- src/testdir/dumps/Test_smooth_long_11.dump 2022-12-31 14:57:51.897227088 +0000 *************** *** 3,6 **** |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 >f|o|u|r| @35 ! @22|4|,|1| @10|B|o|t| --- 3,6 ---- |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 >f|o|u|r| @35 ! |:|s|e|t| |s|c|r|o|l@1|o| @9|4|,|1| @10|B|o|t| *** ../vim-9.0.1120/src/testdir/dumps/Test_smooth_long_12.dump 2022-11-19 12:24:39.758174328 +0000 --- src/testdir/dumps/Test_smooth_long_12.dump 2022-12-31 14:57:51.897227088 +0000 *************** *** 1,6 **** ! |<+0#4040ff13#ffffff0@2|t+0#0000000&|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t ! |h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o ! |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 ! |f|o|u>r| @35 ! @22|4|,|4| @10|B|o|t| --- 1,6 ---- ! |<+0#4040ff13#ffffff0@2|o+0#0000000&|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 ! >f|o|u|r| @35 ! |~+0#4040ff13&| @38 ! |~| @38 ! |:+0#0000000&|s|e|t| |s|c|r|o|l@1|o| @9|4|,|1| @10|B|o|t| *** ../vim-9.0.1120/src/testdir/dumps/Test_smooth_long_13.dump 2022-12-31 15:12:22.742782213 +0000 --- src/testdir/dumps/Test_smooth_long_13.dump 2022-12-31 14:57:51.897227088 +0000 *************** *** 0 **** --- 1,6 ---- + >f+0&#ffffff0|o|u|r| @35 + |~+0#4040ff13&| @38 + |~| @38 + |~| @38 + |~| @38 + | +0#0000000&@21|4|,|1| @10|B|o|t| *** ../vim-9.0.1120/src/testdir/dumps/Test_smooth_long_14.dump 2022-12-31 15:12:22.746782194 +0000 --- src/testdir/dumps/Test_smooth_long_14.dump 2022-12-31 14:57:51.897227088 +0000 *************** *** 0 **** --- 1,6 ---- + |<+0#4040ff13#ffffff0@2|t+0#0000000&|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t + |h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o + |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o + |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 + >f|o|u|r| @35 + @22|4|,|1| @10|B|o|t| *** ../vim-9.0.1120/src/testdir/dumps/Test_smooth_long_15.dump 2022-12-31 15:12:22.750782180 +0000 --- src/testdir/dumps/Test_smooth_long_15.dump 2022-12-31 14:57:51.897227088 +0000 *************** *** 0 **** --- 1,6 ---- + |<+0#4040ff13#ffffff0@2|t+0#0000000&|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t + |h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o + |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o + |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 + |f|o|u>r| @35 + @22|4|,|4| @10|B|o|t| *** ../vim-9.0.1120/src/testdir/dumps/Test_smooth_long_8.dump 2022-11-19 12:24:39.758174328 +0000 --- src/testdir/dumps/Test_smooth_long_8.dump 2022-12-31 14:57:51.897227088 +0000 *************** *** 3,6 **** |t|s| |o|f| |t|e|x>t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w ! |:|s|e|t| |s|c|r|o|l@1|o| @9|3|,|1|3|0| @8|6@1|%| --- 3,6 ---- |t|s| |o|f| |t|e|x>t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w ! | @21|3|,|1|3|0| @8|6@1|%| *** ../vim-9.0.1120/src/testdir/dumps/Test_smooth_long_9.dump 2022-12-03 18:35:04.244951282 +0000 --- src/testdir/dumps/Test_smooth_long_9.dump 2022-12-31 14:57:51.897227088 +0000 *************** *** 3,6 **** |t|s| |o|f| |t|e|x>t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w ! |:|s|e|t| |s|c|r|o|l@1|o| @9|3|,|1|3|0| @8|6@1|%| --- 3,6 ---- |t|s| |o|f| |t|e|x>t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w ! | @21|3|,|1|3|0| @8|6@1|%| *** ../vim-9.0.1120/src/version.c 2022-12-31 14:46:49.805459113 +0000 --- src/version.c 2022-12-31 15:00:07.117178641 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1121, /**/ -- Dogs must have a permit signed by the mayor in order to congregate in groups of three or more on private property. [real standing law in Oklahoma, United States of America] /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///