patch 9.1.1108: 'smoothscroll' gets stuck with 'listchars' "eol" Commit: https://github.com/vim/vim/commit/2c47ab8fcd7188fa87053c757ea86b0d846c06c1 Author: zeertzjq <zeert...@outlook.com> Date: Thu Feb 13 20:34:34 2025 +0100
patch 9.1.1108: 'smoothscroll' gets stuck with 'listchars' "eol" Problem: 'smoothscroll' gets stuck with 'listchars' "eol". Solution: Count size of 'listchars' "eol" in line size when scrolling. (zeertzjq) related: neovim/neovim#32405 closes: #16627 Signed-off-by: zeertzjq <zeert...@outlook.com> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/src/change.c b/src/change.c index 72d01c51a..fb33971e1 100644 --- a/src/change.c +++ b/src/change.c @@ -572,8 +572,7 @@ changed_common( && (last < wp->w_topline || (wp->w_topline >= lnum && wp->w_topline < lnume - && win_linetabsize(wp, wp->w_topline, - ml_get(wp->w_topline), (colnr_T)MAXCOL) + && linetabsize_eol(wp, wp->w_topline) <= wp->w_skipcol + sms_marker_overlap(wp, -1)))) wp->w_skipcol = 0; diff --git a/src/charset.c b/src/charset.c index b4bc812fa..9c68d4af7 100644 --- a/src/charset.c +++ b/src/charset.c @@ -821,6 +821,7 @@ linetabsize_col(int startcol, char_u *s) /* * Like linetabsize_str(), but for a given window instead of the current one. + * Doesn't count the size of 'listchars' "eol". */ int win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len) @@ -836,14 +837,25 @@ win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len) /* * Return the number of cells line "lnum" of window "wp" will take on the * screen, taking into account the size of a tab and text properties. + * Doesn't count the size of 'listchars' "eol". */ - int + int linetabsize(win_T *wp, linenr_T lnum) { return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum, FALSE), (colnr_T)MAXCOL); } +/* + * Like linetabsize(), but counts the size of 'listchars' "eol". + */ + int +linetabsize_eol(win_T *wp, linenr_T lnum) +{ + return linetabsize(wp, lnum) + + ((wp->w_p_list && wp->w_lcs_chars.eol != NUL) ? 1 : 0); +} + /* * Like linetabsize(), but excludes 'above'/'after'/'right'/'below' aligned * virtual text, while keeping inline virtual text. diff --git a/src/misc2.c b/src/misc2.c index dc0d83f5a..a2978e558 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -168,7 +168,7 @@ coladvance2( && wcol >= (colnr_T)width && width > 0) { - csize = linetabsize(curwin, pos->lnum); + csize = linetabsize_eol(curwin, pos->lnum); if (csize > 0) csize--; diff --git a/src/move.c b/src/move.c index ed252d9db..5d34947a5 100644 --- a/src/move.c +++ b/src/move.c @@ -1621,7 +1621,7 @@ f_virtcol2col(typval_T *argvars UNUSED, typval_T *rettv) */ static void cursor_correct_sms(void) { - if (!curwin->w_p_sms ||!curwin->w_p_wrap + if (!curwin->w_p_sms || !curwin->w_p_wrap || curwin->w_cursor.lnum != curwin->w_topline) return; @@ -1631,8 +1631,7 @@ static void cursor_correct_sms(void) int so_cols = so == 0 ? 0 : width1 + (so - 1) * width2; int space_cols = (curwin->w_height - 1) * width2; int overlap, top, bot; - int size = so == 0 ? 0 : win_linetabsize(curwin, curwin->w_topline, - ml_get(curwin->w_topline), (colnr_T)MAXCOL); + int size = so == 0 ? 0 : linetabsize_eol(curwin, curwin->w_topline); if (curwin->w_topline == 1 && curwin->w_skipcol == 0) so_cols = 0; // Ignore 'scrolloff' at top of buffer. @@ -1645,10 +1644,10 @@ static void cursor_correct_sms(void) if (so_cols >= width1 && so_cols > size) so_cols -= width1; - // If there is no marker or we have non-zero scrolloff, just ignore it. - overlap = (curwin->w_skipcol == 0 || so_cols != 0) ? 0 - : sms_marker_overlap(curwin, -1); - top = curwin->w_skipcol + overlap + so_cols; + overlap = curwin->w_skipcol == 0 ? 0 + : sms_marker_overlap(curwin, curwin->w_width - width2); + // If we have non-zero scrolloff, ignore marker overlap. + top = curwin->w_skipcol + (so_cols != 0 ? so_cols : overlap); bot = curwin->w_skipcol + width1 + (curwin->w_height - 1) * width2 - so_cols; validate_virtcol(); @@ -1667,12 +1666,28 @@ static void cursor_correct_sms(void) if (col != curwin->w_virtcol) { + int rc; + curwin->w_curswant = col; - coladvance(curwin->w_curswant); + rc = coladvance(curwin->w_curswant); // validate_virtcol() marked various things as valid, but after // moving the cursor they need to be recomputed curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); + if (rc == FAIL && curwin->w_skipcol > 0 + && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) + { + validate_virtcol(); + if (curwin->w_virtcol < curwin->w_skipcol + overlap) + { + // Cursor still not visible: move it to the next line instead. + curwin->w_cursor.lnum++; + curwin->w_cursor.col = 0; + curwin->w_cursor.coladd = 0; + curwin->w_curswant = 0; + curwin->w_valid &= ~VALID_VIRTCOL; + } + } } } @@ -1813,8 +1828,7 @@ scrolldown( #endif if (do_sms) { - int size = win_linetabsize(curwin, curwin->w_topline, - ml_get(curwin->w_topline), (colnr_T)MAXCOL); + int size = linetabsize_eol(curwin, curwin->w_topline); if (size > width1) { curwin->w_skipcol = width1; @@ -1911,7 +1925,7 @@ scrollup( colnr_T prev_skipcol = curwin->w_skipcol; if (do_sms) - size = linetabsize(curwin, curwin->w_topline); + size = linetabsize_eol(curwin, curwin->w_topline); // diff mode: first consume "topfill" // 'smoothscroll': increase "w_skipcol" until it goes over the end of @@ -1966,7 +1980,7 @@ scrollup( # endif curwin->w_skipcol = 0; if (todo > 1 && do_sms) - size = linetabsize(curwin, curwin->w_topline); + size = linetabsize_eol(curwin, curwin->w_topline); } } } @@ -2043,7 +2057,7 @@ adjust_skipcol(void) } validate_virtcol(); - overlap = sms_marker_overlap(curwin, -1); + overlap = sms_marker_overlap(curwin, curwin->w_width - width2); while (curwin->w_skipcol > 0 && curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) { @@ -2066,8 +2080,7 @@ adjust_skipcol(void) // Avoid adjusting for 'scrolloff' beyond the text line height. if (scrolloff_cols > 0) { - int size = win_linetabsize(curwin, curwin->w_topline, - ml_get(curwin->w_topline), (colnr_T)MAXCOL); + int size = linetabsize_eol(curwin, curwin->w_topline); size = width1 + width2 * ((size - width1 + width2 - 1) / width2); while (col > size) col -= width2; diff --git a/src/normal.c b/src/normal.c index 6cf2b9d2f..1189737c3 100644 --- a/src/normal.c +++ b/src/normal.c @@ -5764,7 +5764,7 @@ nv_g_home_m_cmd(cmdarg_T *cap) // that skipcol is not adjusted later. if (curwin->w_skipcol > 0 && curwin->w_cursor.lnum == curwin->w_topline) { - int overlap = sms_marker_overlap(curwin, -1); + int overlap = sms_marker_overlap(curwin, curwin->w_width - width2); if (overlap > 0 && i == curwin->w_skipcol) i += overlap; } diff --git a/src/proto/charset.pro b/src/proto/charset.pro index 54af280e9..bf1fc1026 100644 --- a/src/proto/charset.pro +++ b/src/proto/charset.pro @@ -22,6 +22,7 @@ int linetabsize_str(char_u *s); int linetabsize_col(int startcol, char_u *s); int win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len); int linetabsize(win_T *wp, linenr_T lnum); +int linetabsize_eol(win_T *wp, linenr_T lnum); int linetabsize_no_outer(win_T *wp, linenr_T lnum); void win_linetabsize_cts(chartabsize_T *cts, colnr_T len); int vim_isIDc(int c); diff --git a/src/testdir/test_scroll_opt.vim b/src/testdir/test_scroll_opt.vim index 9c4e29ed2..7573db9ac 100644 --- a/src/testdir/test_scroll_opt.vim +++ b/src/testdir/test_scroll_opt.vim @@ -1216,4 +1216,59 @@ func Test_smooth_long_scrolloff() call StopVimInTerminal(buf) endfunc +func Test_smoothscroll_listchars_eol() + call NewWindow(10, 40) + setlocal list listchars=eol:$ scrolloff=0 smoothscroll + call setline(1, repeat('-', 40)) + call append(1, repeat(['foobar'], 10)) + + normal! G + call assert_equal(2, line('w0')) + call assert_equal(0, winsaveview().skipcol) + + exe "normal! \<C-Y>" + call assert_equal(1, line('w0')) + call assert_equal(40, winsaveview().skipcol) + + exe "normal! \<C-Y>" + call assert_equal(1, line('w0')) + call assert_equal(0, winsaveview().skipcol) + + exe "normal! \<C-Y>" + call assert_equal(1, line('w0')) + call assert_equal(0, winsaveview().skipcol) + + exe "normal! \<C-E>" + call assert_equal(1, line('w0')) + call assert_equal(40, winsaveview().skipcol) + + exe "normal! \<C-E>" + call assert_equal(2, line('w0')) + call assert_equal(0, winsaveview().skipcol) + + for ve in ['', 'all', 'onemore'] + let &virtualedit = ve + normal! gg + call assert_equal(1, line('w0')) + call assert_equal(0, winsaveview().skipcol) + + exe "normal! \<C-E>" + redraw " redrawing should not cause another scroll + call assert_equal(1, line('w0')) + call assert_equal(40, winsaveview().skipcol) + + exe "normal! \<C-E>" + redraw + call assert_equal(2, line('w0')) + call assert_equal(0, winsaveview().skipcol) + + if ve != 'all' + call assert_equal([0, 2, 1, 0], getpos('.')) + endif + endfor + + set virtualedit& + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 418fcb7ec..8854292e1 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1108, /**/ 1107, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1tif8z-0070Qu-Bs%40256bit.org.