# HG changeset patch # User Christian Brabandt # Date 1695591904 -7200 # Node ID e385bda5e3459652776c9c128c1566a2f3fb64a3 # Parent ec6ad1fcb7eef8a82c3f0b17824f1f18b61f765a patch 9.0.1938: multispace wrong when scrolling horizontally Commit: https://github.com/vim/vim/commit/abc808112ee5df58a9f612f2bb5a65389c2c14e1 Author: zeertzjq Date: Sun Sep 24 23:32:18 2023 +0200 patch 9.0.1938: multispace wrong when scrolling horizontally Problem: multispace wrong when scrolling horizontally Solution: Update position in "multispace" or "leadmultispace" also in skipped chars. Reorder conditions to be more consistent. closes: #13145 closes: #13147 Signed-off-by: Christian Brabandt Co-authored-by: zeertzjq diff --git a/src/drawline.c b/src/drawline.c --- a/src/drawline.c +++ b/src/drawline.c @@ -1684,6 +1684,27 @@ win_line( cts.cts_vcol += charsize; prev_ptr = cts.cts_ptr; MB_PTR_ADV(cts.cts_ptr); + if (wp->w_p_list) + { + in_multispace = *prev_ptr == ' ' && (*cts.cts_ptr == ' ' + || (prev_ptr > line && prev_ptr[-1] == ' ')); + if (!in_multispace) + multispace_pos = 0; + else if (cts.cts_ptr >= line + leadcol + && wp->w_lcs_chars.multispace != NULL) + { + ++multispace_pos; + if (wp->w_lcs_chars.multispace[multispace_pos] == NUL) + multispace_pos = 0; + } + else if (cts.cts_ptr < line + leadcol + && wp->w_lcs_chars.leadmultispace != NULL) + { + ++multispace_pos; + if (wp->w_lcs_chars.leadmultispace[multispace_pos] == NUL) + multispace_pos = 0; + } + } } wlv.vcol = cts.cts_vcol; ptr = cts.cts_ptr; @@ -2589,9 +2610,7 @@ win_line( #ifdef FEAT_LINEBREAK int c0; #endif -#ifdef FEAT_SPELL char_u *prev_ptr = ptr; -#endif // Get a character from the line itself. c = *ptr; @@ -2941,10 +2960,13 @@ win_line( } } #endif - in_multispace = c == ' ' - && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' '); - if (!in_multispace) - multispace_pos = 0; + if (wp->w_p_list) + { + in_multispace = c == ' ' && (*ptr == ' ' + || (prev_ptr > line && prev_ptr[-1] == ' ')); + if (!in_multispace) + multispace_pos = 0; + } // 'list': Change char 160 to 'nbsp' and space to 'space' // setting in 'listchars'. But not when the character is diff --git a/src/message.c b/src/message.c --- a/src/message.c +++ b/src/message.c @@ -2005,10 +2005,13 @@ msg_prt_line(char_u *s, int list) { attr = 0; c = *s++; - in_multispace = c == ' ' - && ((col > 0 && s[-2] == ' ') || *s == ' '); - if (!in_multispace) - multispace_pos = 0; + if (list) + { + in_multispace = c == ' ' && (*s == ' ' + || (col > 0 && s[-2] == ' ')); + if (!in_multispace) + multispace_pos = 0; + } if (c == TAB && (!list || curwin->w_lcs_chars.tab1)) { // tab amount depends on current column @@ -2062,7 +2065,7 @@ msg_prt_line(char_u *s, int list) } else if (c == ' ') { - if (list && lead != NULL && s <= lead && in_multispace + if (lead != NULL && s <= lead && in_multispace && curwin->w_lcs_chars.leadmultispace != NULL) { c = curwin->w_lcs_chars.leadmultispace[multispace_pos++]; @@ -2082,7 +2085,7 @@ msg_prt_line(char_u *s, int list) c = curwin->w_lcs_chars.trail; attr = HL_ATTR(HLF_8); } - else if (list && in_multispace + else if (in_multispace && curwin->w_lcs_chars.multispace != NULL) { c = curwin->w_lcs_chars.multispace[multispace_pos++]; diff --git a/src/testdir/test_listchars.vim b/src/testdir/test_listchars.vim --- a/src/testdir/test_listchars.vim +++ b/src/testdir/test_listchars.vim @@ -4,6 +4,36 @@ source check.vim source view_util.vim source screendump.vim +func Check_listchars(expected, end_lnum, end_scol = -1, leftcol = 0) + if a:leftcol > 0 + let save_wrap = &wrap + set nowrap + call cursor(1, 1) + exe 'normal! ' .. a:leftcol .. 'zl' + endif + + redraw! + for i in range(1, a:end_lnum) + if a:leftcol > 0 + let col = virtcol2col(0, i, a:leftcol) + let col += getline(i)->strpart(col - 1, 1, v:true)->len() + call cursor(i, col) + redraw + call assert_equal(a:leftcol, winsaveview().leftcol) + else + call cursor(i, 1) + end + + let end_scol = a:end_scol < 0 ? '$'->virtcol() - a:leftcol : a:end_scol + call assert_equal([a:expected[i - 1]->strcharpart(a:leftcol)], + \ ScreenLines(i, end_scol)) + endfor + + if a:leftcol > 0 + let &wrap = save_wrap + endif +endfunc + func Test_listchars() enew! set ff=unix @@ -24,11 +54,8 @@ func Test_listchars() \ 'dd........ee<<>-$', \ '<$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, '$'->virtcol())) - endfor + call Check_listchars(expected, 5) + call Check_listchars(expected, 4, -1, 5) set listchars-=trail:< let expected = [ @@ -38,11 +65,8 @@ func Test_listchars() \ 'dd........ee..>-$', \ '.$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 5) + call Check_listchars(expected, 4, -1, 5) " tab with 3rd character. set listchars-=tab:>- @@ -54,11 +78,8 @@ func Test_listchars() \ 'dd........ee--<>$', \ '-$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 5) + call Check_listchars(expected, 4, -1, 5) " tab with 3rd character and linebreak set set listchars-=tab:<=> @@ -71,11 +92,7 @@ func Test_listchars() \ 'dd........ee--<>$', \ '-$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 5) set nolinebreak set listchars-=tab:<·> set listchars+=tab:<=> @@ -88,11 +105,8 @@ func Test_listchars() \ 'dd........ee..<>$', \ '.$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor + call Check_listchars(expected, 5) + call Check_listchars(expected, 4, -1, 5) set listchars-=tab:<=> set listchars+=tab:>- @@ -110,7 +124,8 @@ func Test_listchars() \ '..fff>--<<$', \ '>-------gg>-----$', \ '.....h>-$', - \ 'iii<<<<><<$', '$'], l) + \ 'iii<<<<><<$', + \ '$'], l) " Test lead and trail normal ggdG @@ -132,14 +147,10 @@ func Test_listchars() \ 'h<<<<<<<<<<<$', \ '<<<<<<<<<<<<$', \ '>>>>0xx0<<<<$', - \ '$' + \ '$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " Test multispace @@ -162,14 +173,10 @@ func Test_listchars() \ ' hyYzZyYzZyY$', \ 'yYzZyYzZyYj $', \ 'yYzZ0yY0yYzZ$', - \ '$' + \ '$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " Test leadmultispace + multispace @@ -192,15 +199,14 @@ func Test_listchars() \ ' hyYzZyYzZyY$', \ '.-+*.-+*.-j $', \ '.-+*0yY0yYzZ$', - \ '$' + \ '$' \ ] - redraw! call assert_equal('eol:$,multispace:yYzZ,nbsp:S,leadmultispace:.-+*', &listchars) - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 1) + call Check_listchars(expected, 5, -1, 2) + call Check_listchars(expected, 5, -1, 3) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " Test leadmultispace without multispace @@ -223,16 +229,14 @@ func Test_listchars() \ '+h>>>>>>>>>>$', \ '.-+*.-+*.-j>$', \ '.-+*0++0>>>>$', - \ '$', + \ '$' \ ] - - redraw! call assert_equal('eol:$,nbsp:S,leadmultispace:.-+*,space:+,trail:>,eol:$', &listchars) - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 1) + call Check_listchars(expected, 5, -1, 2) + call Check_listchars(expected, 5, -1, 3) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " Test leadmultispace only @@ -255,14 +259,10 @@ func Test_listchars() \ ' h ', \ '.-+*.-+*.-j ', \ '.-+*0 0 ', - \ ' ', + \ ' ' \ ] - redraw! call assert_equal('leadmultispace:.-+*', &listchars) - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, 12)) - endfor + call Check_listchars(expected, 5, 12) call assert_equal(expected, split(execute("%list"), "\n")) " Test leadmultispace and lead and space @@ -286,14 +286,14 @@ func Test_listchars() \ ',trail:< @@ -326,14 +322,10 @@ func Test_listchars() \ '>h<<<<<<<<<<$', \ '>>>>>>>>>>j<$', \ '>>>>0Xy0<<<<$', - \ '$' + \ '$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " removing 'multispace:' @@ -346,14 +338,10 @@ func Test_listchars() \ '>h<<<<<<<<<<$', \ '>>>>>>>>>>j<$', \ '>>>>0xx0<<<<$', - \ '$' + \ '$' \ ] - redraw! - for i in range(1, 5) - call cursor(i, 1) - call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) - endfor - + call Check_listchars(expected, 6) + call Check_listchars(expected, 5, -1, 6) call assert_equal(expected, split(execute("%list"), "\n")) " test nbsp @@ -365,15 +353,10 @@ func Test_listchars() call append(0, [ ">" .. nbsp .. "<" ]) let expected = '>X< ' - - redraw! - call cursor(1, 1) - call assert_equal([expected], ScreenLines(1, virtcol('$'))) + call Check_listchars([expected], 1) set listchars=nbsp:X - redraw! - call cursor(1, 1) - call assert_equal([expected], ScreenLines(1, virtcol('$'))) + call Check_listchars([expected], 1) " test extends normal ggdG @@ -383,16 +366,11 @@ func Test_listchars() call append(0, [ repeat('A', &columns + 1) ]) let expected = repeat('A', &columns) - - redraw! - call cursor(1, 1) - call assert_equal([expected], ScreenLines(1, &columns)) + call Check_listchars([expected], 1, &columns) set list let expected = expected[:-2] . 'Z' - redraw! - call cursor(1, 1) - call assert_equal([expected], ScreenLines(1, &columns)) + call Check_listchars([expected], 1, &columns) enew! set listchars& ff& @@ -411,19 +389,20 @@ func Test_listchars_unicode() let nbsp = nr2char(0xa0) call append(0, [" a\tb c" .. nbsp .. "d "]) let expected = ['≡≢≣≡≢≣≡≢a←↔↔↔↔↔→b␣c≠d≡≢⇔'] - redraw! - call cursor(1, 1) - call assert_equal(expected, ScreenLines(1, virtcol('$'))) + call Check_listchars(expected, 1) + call Check_listchars(expected, 1, -1, 3) + call Check_listchars(expected, 1, -1, 13) set listchars=eol:\\u21d4,space:\\u2423,multispace:≡\\u2262\\U00002263,nbsp:\\U00002260,tab:←↔\\u2192 - redraw! - call assert_equal(expected, ScreenLines(1, virtcol('$'))) + call Check_listchars(expected, 1) + call Check_listchars(expected, 1, -1, 3) + call Check_listchars(expected, 1, -1, 13) set listchars+=lead:⇨,trail:⇦ let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔'] - redraw! - call cursor(1, 1) - call assert_equal(expected, ScreenLines(1, virtcol('$'))) + call Check_listchars(expected, 1) + call Check_listchars(expected, 1, -1, 3) + call Check_listchars(expected, 1, -1, 13) let &encoding=oldencoding enew! @@ -515,9 +494,7 @@ func Test_listchars_composing() let expected = [ \ "_ \u3099^I \u309A=" .. nbsp1 .. "\u0302=" .. nbsp2 .. "\u0302$" \ ] - redraw! - call cursor(1, 1) - call assert_equal(expected, ScreenLines(1, virtcol('$'))) + call Check_listchars(expected, 1) let &encoding=oldencoding enew! set listchars& ff& diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1938, +/**/ 1937, /**/ 1936,