changeset 33349:e385bda5e345 v9.0.1938

patch 9.0.1938: multispace wrong when scrolling horizontally Commit: https://github.com/vim/vim/commit/abc808112ee5df58a9f612f2bb5a65389c2c14e1 Author: zeertzjq <zeertzjq@outlook.com> 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 <cb@256bit.org> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
author Christian Brabandt <cb@256bit.org>
date Sun, 24 Sep 2023 23:45:04 +0200
parents ec6ad1fcb7ee
children fa58dcaa112e
files src/drawline.c src/message.c src/testdir/test_listchars.vim src/version.c
diffstat 4 files changed, 129 insertions(+), 125 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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++];
--- 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()
 	      \ '<h----------$',
 	      \ '.-+*.-+*.-j-$',
 	      \ '.-+*0--0----$',
-        \ '$',
+	      \ '$'
 	      \ ]
-  redraw!
   call assert_equal('eol:$,lead:<,space:-,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"))
 
   " the last occurrence of 'multispace:' is used
@@ -307,15 +307,11 @@ func Test_listchars()
 	      \ 'xhXyYXyYXyYX$',
 	      \ 'XyYXyYXyYXjx$',
 	      \ 'XyYX0Xy0XyYX$',
-        \ '$'
+	      \ '$'
 	      \ ]
-  redraw!
   call assert_equal('eol:$,multispace:yYzZ,space:x,multispace:XyY', &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, 6)
   call assert_equal(expected, split(execute("%list"), "\n"))
 
   set listchars+=lead:>,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&
--- 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,