Skip to content

Commit 2c47ab8

Browse files
zeertzjqchrisbra
authored andcommitted
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 <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent c0b7ca4 commit 2c47ab8

File tree

8 files changed

+102
-20
lines changed

8 files changed

+102
-20
lines changed

src/change.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,7 @@ changed_common(
572572
&& (last < wp->w_topline
573573
|| (wp->w_topline >= lnum
574574
&& wp->w_topline < lnume
575-
&& win_linetabsize(wp, wp->w_topline,
576-
ml_get(wp->w_topline), (colnr_T)MAXCOL)
575+
&& linetabsize_eol(wp, wp->w_topline)
577576
<= wp->w_skipcol + sms_marker_overlap(wp, -1))))
578577
wp->w_skipcol = 0;
579578

src/charset.c

+13-1
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,7 @@ linetabsize_col(int startcol, char_u *s)
821821

822822
/*
823823
* Like linetabsize_str(), but for a given window instead of the current one.
824+
* Doesn't count the size of 'listchars' "eol".
824825
*/
825826
int
826827
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)
836837
/*
837838
* Return the number of cells line "lnum" of window "wp" will take on the
838839
* screen, taking into account the size of a tab and text properties.
840+
* Doesn't count the size of 'listchars' "eol".
839841
*/
840-
int
842+
int
841843
linetabsize(win_T *wp, linenr_T lnum)
842844
{
843845
return win_linetabsize(wp, lnum,
844846
ml_get_buf(wp->w_buffer, lnum, FALSE), (colnr_T)MAXCOL);
845847
}
846848

849+
/*
850+
* Like linetabsize(), but counts the size of 'listchars' "eol".
851+
*/
852+
int
853+
linetabsize_eol(win_T *wp, linenr_T lnum)
854+
{
855+
return linetabsize(wp, lnum)
856+
+ ((wp->w_p_list && wp->w_lcs_chars.eol != NUL) ? 1 : 0);
857+
}
858+
847859
/*
848860
* Like linetabsize(), but excludes 'above'/'after'/'right'/'below' aligned
849861
* virtual text, while keeping inline virtual text.

src/misc2.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ coladvance2(
168168
&& wcol >= (colnr_T)width
169169
&& width > 0)
170170
{
171-
csize = linetabsize(curwin, pos->lnum);
171+
csize = linetabsize_eol(curwin, pos->lnum);
172172
if (csize > 0)
173173
csize--;
174174

src/move.c

+28-15
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,7 @@ f_virtcol2col(typval_T *argvars UNUSED, typval_T *rettv)
16211621
*/
16221622
static void cursor_correct_sms(void)
16231623
{
1624-
if (!curwin->w_p_sms ||!curwin->w_p_wrap
1624+
if (!curwin->w_p_sms || !curwin->w_p_wrap
16251625
|| curwin->w_cursor.lnum != curwin->w_topline)
16261626
return;
16271627

@@ -1631,8 +1631,7 @@ static void cursor_correct_sms(void)
16311631
int so_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
16321632
int space_cols = (curwin->w_height - 1) * width2;
16331633
int overlap, top, bot;
1634-
int size = so == 0 ? 0 : win_linetabsize(curwin, curwin->w_topline,
1635-
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
1634+
int size = so == 0 ? 0 : linetabsize_eol(curwin, curwin->w_topline);
16361635

16371636
if (curwin->w_topline == 1 && curwin->w_skipcol == 0)
16381637
so_cols = 0; // Ignore 'scrolloff' at top of buffer.
@@ -1645,10 +1644,10 @@ static void cursor_correct_sms(void)
16451644
if (so_cols >= width1 && so_cols > size)
16461645
so_cols -= width1;
16471646

1648-
// If there is no marker or we have non-zero scrolloff, just ignore it.
1649-
overlap = (curwin->w_skipcol == 0 || so_cols != 0) ? 0
1650-
: sms_marker_overlap(curwin, -1);
1651-
top = curwin->w_skipcol + overlap + so_cols;
1647+
overlap = curwin->w_skipcol == 0 ? 0
1648+
: sms_marker_overlap(curwin, curwin->w_width - width2);
1649+
// If we have non-zero scrolloff, ignore marker overlap.
1650+
top = curwin->w_skipcol + (so_cols != 0 ? so_cols : overlap);
16521651
bot = curwin->w_skipcol + width1 + (curwin->w_height - 1) * width2
16531652
- so_cols;
16541653
validate_virtcol();
@@ -1667,12 +1666,28 @@ static void cursor_correct_sms(void)
16671666

16681667
if (col != curwin->w_virtcol)
16691668
{
1669+
int rc;
1670+
16701671
curwin->w_curswant = col;
1671-
coladvance(curwin->w_curswant);
1672+
rc = coladvance(curwin->w_curswant);
16721673
// validate_virtcol() marked various things as valid, but after
16731674
// moving the cursor they need to be recomputed
16741675
curwin->w_valid &=
16751676
~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
1677+
if (rc == FAIL && curwin->w_skipcol > 0
1678+
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
1679+
{
1680+
validate_virtcol();
1681+
if (curwin->w_virtcol < curwin->w_skipcol + overlap)
1682+
{
1683+
// Cursor still not visible: move it to the next line instead.
1684+
curwin->w_cursor.lnum++;
1685+
curwin->w_cursor.col = 0;
1686+
curwin->w_cursor.coladd = 0;
1687+
curwin->w_curswant = 0;
1688+
curwin->w_valid &= ~VALID_VIRTCOL;
1689+
}
1690+
}
16761691
}
16771692
}
16781693

@@ -1813,8 +1828,7 @@ scrolldown(
18131828
#endif
18141829
if (do_sms)
18151830
{
1816-
int size = win_linetabsize(curwin, curwin->w_topline,
1817-
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
1831+
int size = linetabsize_eol(curwin, curwin->w_topline);
18181832
if (size > width1)
18191833
{
18201834
curwin->w_skipcol = width1;
@@ -1911,7 +1925,7 @@ scrollup(
19111925
colnr_T prev_skipcol = curwin->w_skipcol;
19121926

19131927
if (do_sms)
1914-
size = linetabsize(curwin, curwin->w_topline);
1928+
size = linetabsize_eol(curwin, curwin->w_topline);
19151929

19161930
// diff mode: first consume "topfill"
19171931
// 'smoothscroll': increase "w_skipcol" until it goes over the end of
@@ -1966,7 +1980,7 @@ scrollup(
19661980
# endif
19671981
curwin->w_skipcol = 0;
19681982
if (todo > 1 && do_sms)
1969-
size = linetabsize(curwin, curwin->w_topline);
1983+
size = linetabsize_eol(curwin, curwin->w_topline);
19701984
}
19711985
}
19721986
}
@@ -2043,7 +2057,7 @@ adjust_skipcol(void)
20432057
}
20442058

20452059
validate_virtcol();
2046-
overlap = sms_marker_overlap(curwin, -1);
2060+
overlap = sms_marker_overlap(curwin, curwin->w_width - width2);
20472061
while (curwin->w_skipcol > 0
20482062
&& curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols)
20492063
{
@@ -2066,8 +2080,7 @@ adjust_skipcol(void)
20662080
// Avoid adjusting for 'scrolloff' beyond the text line height.
20672081
if (scrolloff_cols > 0)
20682082
{
2069-
int size = win_linetabsize(curwin, curwin->w_topline,
2070-
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
2083+
int size = linetabsize_eol(curwin, curwin->w_topline);
20712084
size = width1 + width2 * ((size - width1 + width2 - 1) / width2);
20722085
while (col > size)
20732086
col -= width2;

src/normal.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -5764,7 +5764,7 @@ nv_g_home_m_cmd(cmdarg_T *cap)
57645764
// that skipcol is not adjusted later.
57655765
if (curwin->w_skipcol > 0 && curwin->w_cursor.lnum == curwin->w_topline)
57665766
{
5767-
int overlap = sms_marker_overlap(curwin, -1);
5767+
int overlap = sms_marker_overlap(curwin, curwin->w_width - width2);
57685768
if (overlap > 0 && i == curwin->w_skipcol)
57695769
i += overlap;
57705770
}

src/proto/charset.pro

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ int linetabsize_str(char_u *s);
2222
int linetabsize_col(int startcol, char_u *s);
2323
int win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len);
2424
int linetabsize(win_T *wp, linenr_T lnum);
25+
int linetabsize_eol(win_T *wp, linenr_T lnum);
2526
int linetabsize_no_outer(win_T *wp, linenr_T lnum);
2627
void win_linetabsize_cts(chartabsize_T *cts, colnr_T len);
2728
int vim_isIDc(int c);

src/testdir/test_scroll_opt.vim

+55
Original file line numberDiff line numberDiff line change
@@ -1216,4 +1216,59 @@ func Test_smooth_long_scrolloff()
12161216
call StopVimInTerminal(buf)
12171217
endfunc
12181218

1219+
func Test_smoothscroll_listchars_eol()
1220+
call NewWindow(10, 40)
1221+
setlocal list listchars=eol:$ scrolloff=0 smoothscroll
1222+
call setline(1, repeat('-', 40))
1223+
call append(1, repeat(['foobar'], 10))
1224+
1225+
normal! G
1226+
call assert_equal(2, line('w0'))
1227+
call assert_equal(0, winsaveview().skipcol)
1228+
1229+
exe "normal! \<C-Y>"
1230+
call assert_equal(1, line('w0'))
1231+
call assert_equal(40, winsaveview().skipcol)
1232+
1233+
exe "normal! \<C-Y>"
1234+
call assert_equal(1, line('w0'))
1235+
call assert_equal(0, winsaveview().skipcol)
1236+
1237+
exe "normal! \<C-Y>"
1238+
call assert_equal(1, line('w0'))
1239+
call assert_equal(0, winsaveview().skipcol)
1240+
1241+
exe "normal! \<C-E>"
1242+
call assert_equal(1, line('w0'))
1243+
call assert_equal(40, winsaveview().skipcol)
1244+
1245+
exe "normal! \<C-E>"
1246+
call assert_equal(2, line('w0'))
1247+
call assert_equal(0, winsaveview().skipcol)
1248+
1249+
for ve in ['', 'all', 'onemore']
1250+
let &virtualedit = ve
1251+
normal! gg
1252+
call assert_equal(1, line('w0'))
1253+
call assert_equal(0, winsaveview().skipcol)
1254+
1255+
exe "normal! \<C-E>"
1256+
redraw " redrawing should not cause another scroll
1257+
call assert_equal(1, line('w0'))
1258+
call assert_equal(40, winsaveview().skipcol)
1259+
1260+
exe "normal! \<C-E>"
1261+
redraw
1262+
call assert_equal(2, line('w0'))
1263+
call assert_equal(0, winsaveview().skipcol)
1264+
1265+
if ve != 'all'
1266+
call assert_equal([0, 2, 1, 0], getpos('.'))
1267+
endif
1268+
endfor
1269+
1270+
set virtualedit&
1271+
bwipe!
1272+
endfunc
1273+
12191274
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

+2
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
1108,
707709
/**/
708710
1107,
709711
/**/

0 commit comments

Comments
 (0)