vim-patch:9.0.1938: multispace wrong when scrolling horizontally (#25348)

Problem:  multispace wrong when scrolling horizontally
Solution: Update position in "multispace" or "leadmultispace" also in
          skipped chars. Reorder conditions to be more consistent.

closes: vim/vim#13145
closes: vim/vim#13147

abc808112e
This commit is contained in:
zeertzjq 2023-09-25 06:31:52 +08:00 committed by GitHub
parent 9154fc76b7
commit 7d4967547b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 124 additions and 122 deletions

View File

@ -1539,6 +1539,25 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
cts.cts_vcol += charsize; cts.cts_vcol += charsize;
prev_ptr = cts.cts_ptr; prev_ptr = cts.cts_ptr;
MB_PTR_ADV(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_p_lcs_chars.multispace != NULL) {
multispace_pos++;
if (wp->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
} else if (cts.cts_ptr < line + leadcol
&& wp->w_p_lcs_chars.leadmultispace != NULL) {
multispace_pos++;
if (wp->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
}
}
} }
wlv.vcol = cts.cts_vcol; wlv.vcol = cts.cts_vcol;
ptr = cts.cts_ptr; ptr = cts.cts_ptr;
@ -2367,9 +2386,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
} }
} }
in_multispace = c == ' ' && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' '); if (wp->w_p_list) {
if (!in_multispace) { in_multispace = c == ' ' && (*ptr == ' '
multispace_pos = 0; || (prev_ptr > line && prev_ptr[-1] == ' '));
if (!in_multispace) {
multispace_pos = 0;
}
} }
// 'list': Change char 160 to 'nbsp' and space to 'space'. // 'list': Change char 160 to 'nbsp' and space to 'space'.

View File

@ -1907,10 +1907,13 @@ void msg_prt_line(const char *s, int list)
continue; continue;
} else { } else {
attr = 0; attr = 0;
c = (unsigned char)(*s++); c = (uint8_t)(*s++);
in_multispace = c == ' ' && ((col > 0 && s[-2] == ' ') || *s == ' '); if (list) {
if (!in_multispace) { in_multispace = c == ' ' && (*s == ' '
multispace_pos = 0; || (col > 0 && s[-2] == ' '));
if (!in_multispace) {
multispace_pos = 0;
}
} }
if (c == TAB && (!list || curwin->w_p_lcs_chars.tab1)) { if (c == TAB && (!list || curwin->w_p_lcs_chars.tab1)) {
// tab amount depends on current column // tab amount depends on current column
@ -1950,7 +1953,7 @@ void msg_prt_line(const char *s, int list)
// the same in plain text. // the same in plain text.
attr = HL_ATTR(HLF_0); attr = HL_ATTR(HLF_0);
} else if (c == ' ') { } else if (c == ' ') {
if (list && lead != NULL && s <= lead && in_multispace if (lead != NULL && s <= lead && in_multispace
&& curwin->w_p_lcs_chars.leadmultispace != NULL) { && curwin->w_p_lcs_chars.leadmultispace != NULL) {
c = curwin->w_p_lcs_chars.leadmultispace[multispace_pos++]; c = curwin->w_p_lcs_chars.leadmultispace[multispace_pos++];
if (curwin->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) { if (curwin->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
@ -1963,7 +1966,7 @@ void msg_prt_line(const char *s, int list)
} else if (trail != NULL && s > trail) { } else if (trail != NULL && s > trail) {
c = curwin->w_p_lcs_chars.trail; c = curwin->w_p_lcs_chars.trail;
attr = HL_ATTR(HLF_0); attr = HL_ATTR(HLF_0);
} else if (list && in_multispace } else if (in_multispace
&& curwin->w_p_lcs_chars.multispace != NULL) { && curwin->w_p_lcs_chars.multispace != NULL) {
c = curwin->w_p_lcs_chars.multispace[multispace_pos++]; c = curwin->w_p_lcs_chars.multispace[multispace_pos++];
if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) { if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) {

View File

@ -4,6 +4,36 @@ source check.vim
source view_util.vim source view_util.vim
source screendump.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() func Test_listchars()
enew! enew!
set ff=unix set ff=unix
@ -24,11 +54,8 @@ func Test_listchars()
\ 'dd........ee<<>-$', \ 'dd........ee<<>-$',
\ '<$' \ '<$'
\ ] \ ]
redraw! call Check_listchars(expected, 5)
for i in range(1, 5) call Check_listchars(expected, 4, -1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, '$'->virtcol()))
endfor
set listchars-=trail:< set listchars-=trail:<
let expected = [ let expected = [
@ -38,11 +65,8 @@ func Test_listchars()
\ 'dd........ee..>-$', \ 'dd........ee..>-$',
\ '.$' \ '.$'
\ ] \ ]
redraw! call Check_listchars(expected, 5)
for i in range(1, 5) call Check_listchars(expected, 4, -1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
" tab with 3rd character. " tab with 3rd character.
set listchars-=tab:>- set listchars-=tab:>-
@ -54,11 +78,8 @@ func Test_listchars()
\ 'dd........ee--<>$', \ 'dd........ee--<>$',
\ '-$' \ '-$'
\ ] \ ]
redraw! call Check_listchars(expected, 5)
for i in range(1, 5) call Check_listchars(expected, 4, -1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
" tab with 3rd character and linebreak set " tab with 3rd character and linebreak set
set listchars-=tab:<=> set listchars-=tab:<=>
@ -71,11 +92,7 @@ func Test_listchars()
\ 'dd........ee--<>$', \ 'dd........ee--<>$',
\ '-$' \ '-$'
\ ] \ ]
redraw! call Check_listchars(expected, 5)
for i in range(1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
set nolinebreak set nolinebreak
set listchars-=tab:<·> set listchars-=tab:<·>
set listchars+=tab:<=> set listchars+=tab:<=>
@ -88,11 +105,8 @@ func Test_listchars()
\ 'dd........ee..<>$', \ 'dd........ee..<>$',
\ '.$' \ '.$'
\ ] \ ]
redraw! call Check_listchars(expected, 5)
for i in range(1, 5) call Check_listchars(expected, 4, -1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
set listchars-=tab:<=> set listchars-=tab:<=>
set listchars+=tab:>- set listchars+=tab:>-
@ -110,7 +124,8 @@ func Test_listchars()
\ '..fff>--<<$', \ '..fff>--<<$',
\ '>-------gg>-----$', \ '>-------gg>-----$',
\ '.....h>-$', \ '.....h>-$',
\ 'iii<<<<><<$', '$'], l) \ 'iii<<<<><<$',
\ '$'], l)
" Test lead and trail " Test lead and trail
normal ggdG normal ggdG
@ -132,14 +147,10 @@ func Test_listchars()
\ 'h<<<<<<<<<<<$', \ 'h<<<<<<<<<<<$',
\ '<<<<<<<<<<<<$', \ '<<<<<<<<<<<<$',
\ '>>>>0xx0<<<<$', \ '>>>>0xx0<<<<$',
\ '$' \ '$'
\ ] \ ]
redraw! call Check_listchars(expected, 6)
for i in range(1, 5) call Check_listchars(expected, 5, -1, 6)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" Test multispace " Test multispace
@ -162,14 +173,10 @@ func Test_listchars()
\ ' hyYzZyYzZyY$', \ ' hyYzZyYzZyY$',
\ 'yYzZyYzZyYj $', \ 'yYzZyYzZyYj $',
\ 'yYzZ0yY0yYzZ$', \ 'yYzZ0yY0yYzZ$',
\ '$' \ '$'
\ ] \ ]
redraw! call Check_listchars(expected, 6)
for i in range(1, 5) call Check_listchars(expected, 5, -1, 6)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" Test leadmultispace + multispace " Test leadmultispace + multispace
@ -192,15 +199,14 @@ func Test_listchars()
\ ' hyYzZyYzZyY$', \ ' hyYzZyYzZyY$',
\ '.-+*.-+*.-j $', \ '.-+*.-+*.-j $',
\ '.-+*0yY0yYzZ$', \ '.-+*0yY0yYzZ$',
\ '$' \ '$'
\ ] \ ]
redraw!
call assert_equal('eol:$,multispace:yYzZ,nbsp:S,leadmultispace:.-+*', &listchars) call assert_equal('eol:$,multispace:yYzZ,nbsp:S,leadmultispace:.-+*', &listchars)
for i in range(1, 5) call Check_listchars(expected, 6)
call cursor(i, 1) call Check_listchars(expected, 5, -1, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) call Check_listchars(expected, 5, -1, 2)
endfor call Check_listchars(expected, 5, -1, 3)
call Check_listchars(expected, 5, -1, 6)
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" Test leadmultispace without multispace " Test leadmultispace without multispace
@ -223,16 +229,14 @@ func Test_listchars()
\ '+h>>>>>>>>>>$', \ '+h>>>>>>>>>>$',
\ '.-+*.-+*.-j>$', \ '.-+*.-+*.-j>$',
\ '.-+*0++0>>>>$', \ '.-+*0++0>>>>$',
\ '$', \ '$'
\ ] \ ]
redraw!
call assert_equal('eol:$,nbsp:S,leadmultispace:.-+*,space:+,trail:>,eol:$', &listchars) call assert_equal('eol:$,nbsp:S,leadmultispace:.-+*,space:+,trail:>,eol:$', &listchars)
for i in range(1, 5) call Check_listchars(expected, 6)
call cursor(i, 1) call Check_listchars(expected, 5, -1, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) call Check_listchars(expected, 5, -1, 2)
endfor call Check_listchars(expected, 5, -1, 3)
call Check_listchars(expected, 5, -1, 6)
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" Test leadmultispace only " Test leadmultispace only
@ -255,14 +259,10 @@ func Test_listchars()
\ ' h ', \ ' h ',
\ '.-+*.-+*.-j ', \ '.-+*.-+*.-j ',
\ '.-+*0 0 ', \ '.-+*0 0 ',
\ ' ', \ ' '
\ ] \ ]
redraw!
call assert_equal('leadmultispace:.-+*', &listchars) call assert_equal('leadmultispace:.-+*', &listchars)
for i in range(1, 5) call Check_listchars(expected, 5, 12)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, 12))
endfor
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" Test leadmultispace and lead and space " Test leadmultispace and lead and space
@ -286,14 +286,14 @@ func Test_listchars()
\ '<h----------$', \ '<h----------$',
\ '.-+*.-+*.-j-$', \ '.-+*.-+*.-j-$',
\ '.-+*0--0----$', \ '.-+*0--0----$',
\ '$', \ '$'
\ ] \ ]
redraw!
call assert_equal('eol:$,lead:<,space:-,leadmultispace:.-+*', &listchars) call assert_equal('eol:$,lead:<,space:-,leadmultispace:.-+*', &listchars)
for i in range(1, 5) call Check_listchars(expected, 6)
call cursor(i, 1) call Check_listchars(expected, 5, -1, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) call Check_listchars(expected, 5, -1, 2)
endfor call Check_listchars(expected, 5, -1, 3)
call Check_listchars(expected, 5, -1, 6)
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" the last occurrence of 'multispace:' is used " the last occurrence of 'multispace:' is used
@ -307,15 +307,11 @@ func Test_listchars()
\ 'xhXyYXyYXyYX$', \ 'xhXyYXyYXyYX$',
\ 'XyYXyYXyYXjx$', \ 'XyYXyYXyYXjx$',
\ 'XyYX0Xy0XyYX$', \ 'XyYX0Xy0XyYX$',
\ '$' \ '$'
\ ] \ ]
redraw!
call assert_equal('eol:$,multispace:yYzZ,space:x,multispace:XyY', &listchars) call assert_equal('eol:$,multispace:yYzZ,space:x,multispace:XyY', &listchars)
for i in range(1, 5) call Check_listchars(expected, 6)
call cursor(i, 1) call Check_listchars(expected, 5, -1, 6)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
set listchars+=lead:>,trail:< set listchars+=lead:>,trail:<
@ -326,14 +322,10 @@ func Test_listchars()
\ '>h<<<<<<<<<<$', \ '>h<<<<<<<<<<$',
\ '>>>>>>>>>>j<$', \ '>>>>>>>>>>j<$',
\ '>>>>0Xy0<<<<$', \ '>>>>0Xy0<<<<$',
\ '$' \ '$'
\ ] \ ]
redraw! call Check_listchars(expected, 6)
for i in range(1, 5) call Check_listchars(expected, 5, -1, 6)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" removing 'multispace:' " removing 'multispace:'
@ -346,14 +338,10 @@ func Test_listchars()
\ '>h<<<<<<<<<<$', \ '>h<<<<<<<<<<$',
\ '>>>>>>>>>>j<$', \ '>>>>>>>>>>j<$',
\ '>>>>0xx0<<<<$', \ '>>>>0xx0<<<<$',
\ '$' \ '$'
\ ] \ ]
redraw! call Check_listchars(expected, 6)
for i in range(1, 5) call Check_listchars(expected, 5, -1, 6)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" test nbsp " test nbsp
@ -365,15 +353,10 @@ func Test_listchars()
call append(0, [ ">" .. nbsp .. "<" ]) call append(0, [ ">" .. nbsp .. "<" ])
let expected = '>X< ' let expected = '>X< '
call Check_listchars([expected], 1)
redraw!
call cursor(1, 1)
call assert_equal([expected], ScreenLines(1, virtcol('$')))
set listchars=nbsp:X set listchars=nbsp:X
redraw! call Check_listchars([expected], 1)
call cursor(1, 1)
call assert_equal([expected], ScreenLines(1, virtcol('$')))
" test extends " test extends
normal ggdG normal ggdG
@ -383,16 +366,11 @@ func Test_listchars()
call append(0, [ repeat('A', &columns + 1) ]) call append(0, [ repeat('A', &columns + 1) ])
let expected = repeat('A', &columns) let expected = repeat('A', &columns)
call Check_listchars([expected], 1, &columns)
redraw!
call cursor(1, 1)
call assert_equal([expected], ScreenLines(1, &columns))
set list set list
let expected = expected[:-2] . 'Z' let expected = expected[:-2] . 'Z'
redraw! call Check_listchars([expected], 1, &columns)
call cursor(1, 1)
call assert_equal([expected], ScreenLines(1, &columns))
enew! enew!
set listchars& ff& set listchars& ff&
@ -411,19 +389,20 @@ func Test_listchars_unicode()
let nbsp = nr2char(0xa0) let nbsp = nr2char(0xa0)
call append(0, [" a\tb c" .. nbsp .. "d "]) call append(0, [" a\tb c" .. nbsp .. "d "])
let expected = ['≡≢≣≡≢≣≡≢a←↔↔↔↔↔→b␣c≠d≡≢⇔'] let expected = ['≡≢≣≡≢≣≡≢a←↔↔↔↔↔→b␣c≠d≡≢⇔']
redraw! call Check_listchars(expected, 1)
call cursor(1, 1) call Check_listchars(expected, 1, -1, 3)
call assert_equal(expected, ScreenLines(1, virtcol('$'))) call Check_listchars(expected, 1, -1, 13)
set listchars=eol:\\u21d4,space:\\u2423,multispace:≡\\u2262\\U00002263,nbsp:\\U00002260,tab:←↔\\u2192 set listchars=eol:\\u21d4,space:\\u2423,multispace:≡\\u2262\\U00002263,nbsp:\\U00002260,tab:←↔\\u2192
redraw! call Check_listchars(expected, 1)
call assert_equal(expected, ScreenLines(1, virtcol('$'))) call Check_listchars(expected, 1, -1, 3)
call Check_listchars(expected, 1, -1, 13)
set listchars+=lead:⇨,trail:⇦ set listchars+=lead:⇨,trail:⇦
let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔'] let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔']
redraw! call Check_listchars(expected, 1)
call cursor(1, 1) call Check_listchars(expected, 1, -1, 3)
call assert_equal(expected, ScreenLines(1, virtcol('$'))) call Check_listchars(expected, 1, -1, 13)
let &encoding=oldencoding let &encoding=oldencoding
enew! enew!
@ -515,9 +494,7 @@ func Test_listchars_composing()
let expected = [ let expected = [
\ "_ \u3099^I \u309A=" .. nbsp1 .. "\u0302=" .. nbsp2 .. "\u0302$" \ "_ \u3099^I \u309A=" .. nbsp1 .. "\u0302=" .. nbsp2 .. "\u0302$"
\ ] \ ]
redraw! call Check_listchars(expected, 1)
call cursor(1, 1)
call assert_equal(expected, ScreenLines(1, virtcol('$')))
let &encoding=oldencoding let &encoding=oldencoding
enew! enew!
set listchars& ff& set listchars& ff&