mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
vim-patch:9.1.1108: 'smoothscroll' gets stuck with 'listchars' "eol" (#32434)
Problem: 'smoothscroll' gets stuck with 'listchars' "eol".
Solution: Count size of 'listchars' "eol" in line size when scrolling.
(zeertzjq)
related: neovim/neovim#32405
closes: vim/vim#16627
2c47ab8fcd
This commit is contained in:
@@ -341,8 +341,8 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
|
|||||||
&& (last < wp->w_topline
|
&& (last < wp->w_topline
|
||||||
|| (wp->w_topline >= lnum
|
|| (wp->w_topline >= lnum
|
||||||
&& wp->w_topline < lnume
|
&& wp->w_topline < lnume
|
||||||
&& win_linetabsize(wp, wp->w_topline, ml_get_buf(buf, wp->w_topline), MAXCOL)
|
&& (linetabsize_eol(wp, wp->w_topline)
|
||||||
<= (wp->w_skipcol + sms_marker_overlap(wp, -1))))) {
|
<= wp->w_skipcol + sms_marker_overlap(wp, -1))))) {
|
||||||
wp->w_skipcol = 0;
|
wp->w_skipcol = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -130,7 +130,7 @@ static int coladvance2(win_T *wp, pos_T *pos, bool addspaces, bool finetune, col
|
|||||||
&& wp->w_width_inner != 0
|
&& wp->w_width_inner != 0
|
||||||
&& wcol >= (colnr_T)width
|
&& wcol >= (colnr_T)width
|
||||||
&& width > 0) {
|
&& width > 0) {
|
||||||
csize = linetabsize(wp, pos->lnum);
|
csize = linetabsize_eol(wp, pos->lnum);
|
||||||
if (csize > 0) {
|
if (csize > 0) {
|
||||||
csize--;
|
csize--;
|
||||||
}
|
}
|
||||||
|
@@ -1191,9 +1191,7 @@ static void cursor_correct_sms(win_T *wp)
|
|||||||
int width2 = width1 + win_col_off2(wp);
|
int width2 = width1 + win_col_off2(wp);
|
||||||
int so_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
|
int so_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
|
||||||
int space_cols = (wp->w_height_inner - 1) * width2;
|
int space_cols = (wp->w_height_inner - 1) * width2;
|
||||||
int size = so == 0 ? 0 : win_linetabsize(wp, wp->w_topline,
|
int size = so == 0 ? 0 : linetabsize_eol(wp, wp->w_topline);
|
||||||
ml_get_buf(wp->w_buffer, wp->w_topline),
|
|
||||||
(colnr_T)MAXCOL);
|
|
||||||
|
|
||||||
if (wp->w_topline == 1 && wp->w_skipcol == 0) {
|
if (wp->w_topline == 1 && wp->w_skipcol == 0) {
|
||||||
so_cols = 0; // Ignore 'scrolloff' at top of buffer.
|
so_cols = 0; // Ignore 'scrolloff' at top of buffer.
|
||||||
@@ -1209,9 +1207,10 @@ static void cursor_correct_sms(win_T *wp)
|
|||||||
so_cols -= width1;
|
so_cols -= width1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no marker or we have non-zero scrolloff, just ignore it.
|
int overlap = wp->w_skipcol == 0
|
||||||
int overlap = (wp->w_skipcol == 0 || so_cols != 0) ? 0 : sms_marker_overlap(wp, -1);
|
? 0 : sms_marker_overlap(wp, wp->w_width_inner - width2);
|
||||||
int top = wp->w_skipcol + overlap + so_cols;
|
// If we have non-zero scrolloff, ignore marker overlap.
|
||||||
|
int top = wp->w_skipcol + (so_cols != 0 ? so_cols : overlap);
|
||||||
int bot = wp->w_skipcol + width1 + (wp->w_height_inner - 1) * width2 - so_cols;
|
int bot = wp->w_skipcol + width1 + (wp->w_height_inner - 1) * width2 - so_cols;
|
||||||
|
|
||||||
validate_virtcol(wp);
|
validate_virtcol(wp);
|
||||||
@@ -1232,10 +1231,22 @@ static void cursor_correct_sms(win_T *wp)
|
|||||||
|
|
||||||
if (col != wp->w_virtcol) {
|
if (col != wp->w_virtcol) {
|
||||||
wp->w_curswant = col;
|
wp->w_curswant = col;
|
||||||
coladvance(wp, wp->w_curswant);
|
int rc = coladvance(wp, wp->w_curswant);
|
||||||
// validate_virtcol() marked various things as valid, but after
|
// validate_virtcol() marked various things as valid, but after
|
||||||
// moving the cursor they need to be recomputed
|
// moving the cursor they need to be recomputed
|
||||||
wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
|
wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
|
||||||
|
if (rc == FAIL && wp->w_skipcol > 0
|
||||||
|
&& wp->w_cursor.lnum < wp->w_buffer->b_ml.ml_line_count) {
|
||||||
|
validate_virtcol(wp);
|
||||||
|
if (wp->w_virtcol < wp->w_skipcol + overlap) {
|
||||||
|
// Cursor still not visible: move it to the next line instead.
|
||||||
|
wp->w_cursor.lnum++;
|
||||||
|
wp->w_cursor.col = 0;
|
||||||
|
wp->w_cursor.coladd = 0;
|
||||||
|
wp->w_curswant = 0;
|
||||||
|
wp->w_valid &= ~VALID_VIRTCOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,8 +1359,7 @@ bool scrolldown(win_T *wp, linenr_T line_count, int byfold)
|
|||||||
wp->w_topline = first;
|
wp->w_topline = first;
|
||||||
} else {
|
} else {
|
||||||
if (do_sms) {
|
if (do_sms) {
|
||||||
int size = win_linetabsize(wp, wp->w_topline,
|
int size = linetabsize_eol(wp, wp->w_topline);
|
||||||
ml_get_buf(wp->w_buffer, wp->w_topline), MAXCOL);
|
|
||||||
if (size > width1) {
|
if (size > width1) {
|
||||||
wp->w_skipcol = width1;
|
wp->w_skipcol = width1;
|
||||||
size -= width1;
|
size -= width1;
|
||||||
@@ -1430,7 +1440,7 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold)
|
|||||||
const colnr_T prev_skipcol = wp->w_skipcol;
|
const colnr_T prev_skipcol = wp->w_skipcol;
|
||||||
|
|
||||||
if (do_sms) {
|
if (do_sms) {
|
||||||
size = linetabsize(wp, wp->w_topline);
|
size = linetabsize_eol(wp, wp->w_topline);
|
||||||
}
|
}
|
||||||
|
|
||||||
// diff mode: first consume "topfill"
|
// diff mode: first consume "topfill"
|
||||||
@@ -1473,7 +1483,7 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold)
|
|||||||
wp->w_topfill = win_get_fill(wp, lnum);
|
wp->w_topfill = win_get_fill(wp, lnum);
|
||||||
wp->w_skipcol = 0;
|
wp->w_skipcol = 0;
|
||||||
if (todo > 1 && do_sms) {
|
if (todo > 1 && do_sms) {
|
||||||
size = linetabsize(wp, wp->w_topline);
|
size = linetabsize_eol(wp, wp->w_topline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1540,7 +1550,7 @@ void adjust_skipcol(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate_virtcol(curwin);
|
validate_virtcol(curwin);
|
||||||
int overlap = sms_marker_overlap(curwin, -1);
|
int overlap = sms_marker_overlap(curwin, curwin->w_width_inner - width2);
|
||||||
while (curwin->w_skipcol > 0
|
while (curwin->w_skipcol > 0
|
||||||
&& curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) {
|
&& curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) {
|
||||||
// scroll a screen line down
|
// scroll a screen line down
|
||||||
@@ -1561,8 +1571,7 @@ void adjust_skipcol(void)
|
|||||||
|
|
||||||
// Avoid adjusting for 'scrolloff' beyond the text line height.
|
// Avoid adjusting for 'scrolloff' beyond the text line height.
|
||||||
if (scrolloff_cols > 0) {
|
if (scrolloff_cols > 0) {
|
||||||
int size = win_linetabsize(curwin, curwin->w_topline,
|
int size = linetabsize_eol(curwin, curwin->w_topline);
|
||||||
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
|
|
||||||
size = width1 + width2 * ((size - width1 + width2 - 1) / width2);
|
size = width1 + width2 * ((size - width1 + width2 - 1) / width2);
|
||||||
while (col > size) {
|
while (col > size) {
|
||||||
col -= width2;
|
col -= width2;
|
||||||
|
@@ -5225,7 +5225,7 @@ void nv_g_home_m_cmd(cmdarg_T *cap)
|
|||||||
// When ending up below 'smoothscroll' marker, move just beyond it so
|
// When ending up below 'smoothscroll' marker, move just beyond it so
|
||||||
// that skipcol is not adjusted later.
|
// that skipcol is not adjusted later.
|
||||||
if (curwin->w_skipcol > 0 && curwin->w_cursor.lnum == curwin->w_topline) {
|
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_inner - width2);
|
||||||
if (overlap > 0 && i == curwin->w_skipcol) {
|
if (overlap > 0 && i == curwin->w_skipcol) {
|
||||||
i += overlap;
|
i += overlap;
|
||||||
}
|
}
|
||||||
|
@@ -75,11 +75,19 @@ int linetabsize_col(int startvcol, char *s)
|
|||||||
|
|
||||||
/// Return the number of cells line "lnum" of window "wp" will take on the
|
/// Return the number of cells line "lnum" of window "wp" will take on the
|
||||||
/// screen, taking into account the size of a tab and inline virtual text.
|
/// screen, taking into account the size of a tab and inline virtual text.
|
||||||
|
/// Doesn't count the size of 'listchars' "eol".
|
||||||
int linetabsize(win_T *wp, linenr_T lnum)
|
int linetabsize(win_T *wp, linenr_T lnum)
|
||||||
{
|
{
|
||||||
return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum), MAXCOL);
|
return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum), 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_p_lcs_chars.eol != NUL) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
static const uint32_t inline_filter[4] = {[kMTMetaInline] = kMTFilterSelect };
|
static const uint32_t inline_filter[4] = {[kMTMetaInline] = kMTFilterSelect };
|
||||||
|
|
||||||
/// Prepare the structure passed to charsize functions.
|
/// Prepare the structure passed to charsize functions.
|
||||||
|
@@ -73,6 +73,7 @@ static inline int linetabsize_str(char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Like linetabsize_str(), but for a given window instead of the current one.
|
/// Like linetabsize_str(), but for a given window instead of the current one.
|
||||||
|
/// Doesn't count the size of 'listchars' "eol".
|
||||||
///
|
///
|
||||||
/// @param wp
|
/// @param wp
|
||||||
/// @param line
|
/// @param line
|
||||||
|
@@ -1219,4 +1219,59 @@ func Test_smooth_long_scrolloff()
|
|||||||
call StopVimInTerminal(buf)
|
call StopVimInTerminal(buf)
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
Reference in New Issue
Block a user