patch 9.0.1938: multispace wrong when scrolling horizontally

Commit: 
https://github.com/vim/vim/commit/abc808112ee5df58a9f612f2bb5a65389c2c14e1
Author: zeertzjq <zeert...@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 <c...@256bit.org>
    Co-authored-by: zeertzjq <zeert...@outlook.com>

diff --git a/src/drawline.c b/src/drawline.c
index 95ea3f025..4d63fae34 100644
--- 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
index 98a362411..2fc6cefa9 100644
--- 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
index 2f495c3ab..8628fb20e 100644
--- 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"), "
"))
 
   " 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"), "
"))
 
   " 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"), "
"))
 
   " 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"), "
"))
 
   " 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"), "
"))
 
   " 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"), "
"))
 
   " 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"), "
"))
 
   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"), "
"))
 
   " 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"), "
"))
 
   " 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   b 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
index 7978aa0bf..16e3e8a35 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1938,
 /**/
     1937,
 /**/

-- 
-- 
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 on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qkWuW-00A3vA-Pp%40256bit.org.

Raspunde prin e-mail lui