1" Tests for 'listchars' display with 'list' and :list 2 3source check.vim 4source view_util.vim 5source screendump.vim 6 7func Test_listchars() 8 enew! 9 set ff=unix 10 set list 11 12 set listchars+=tab:>-,space:.,trail:< 13 call append(0, [ 14 \ ' aa ', 15 \ ' bb ', 16 \ ' cccc ', 17 \ 'dd ee ', 18 \ ' ' 19 \ ]) 20 let expected = [ 21 \ '>-------aa>-----$', 22 \ '..bb>---<<$', 23 \ '...cccc><$', 24 \ 'dd........ee<<>-$', 25 \ '<$' 26 \ ] 27 redraw! 28 for i in range(1, 5) 29 call cursor(i, 1) 30 call assert_equal([expected[i - 1]], ScreenLines(i, '$'->virtcol())) 31 endfor 32 33 set listchars-=trail:< 34 let expected = [ 35 \ '>-------aa>-----$', 36 \ '..bb>---..$', 37 \ '...cccc>.$', 38 \ 'dd........ee..>-$', 39 \ '.$' 40 \ ] 41 redraw! 42 for i in range(1, 5) 43 call cursor(i, 1) 44 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 45 endfor 46 47 " tab with 3rd character. 48 set listchars-=tab:>- 49 set listchars+=tab:<=>,trail:- 50 let expected = [ 51 \ '<======>aa<====>$', 52 \ '..bb<==>--$', 53 \ '...cccc>-$', 54 \ 'dd........ee--<>$', 55 \ '-$' 56 \ ] 57 redraw! 58 for i in range(1, 5) 59 call cursor(i, 1) 60 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 61 endfor 62 63 " tab with 3rd character and linebreak set 64 set listchars-=tab:<=> 65 set listchars+=tab:<·> 66 set linebreak 67 let expected = [ 68 \ '<······>aa<····>$', 69 \ '..bb<··>--$', 70 \ '...cccc>-$', 71 \ 'dd........ee--<>$', 72 \ '-$' 73 \ ] 74 redraw! 75 for i in range(1, 5) 76 call cursor(i, 1) 77 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 78 endfor 79 set nolinebreak 80 set listchars-=tab:<·> 81 set listchars+=tab:<=> 82 83 set listchars-=trail:- 84 let expected = [ 85 \ '<======>aa<====>$', 86 \ '..bb<==>..$', 87 \ '...cccc>.$', 88 \ 'dd........ee..<>$', 89 \ '.$' 90 \ ] 91 redraw! 92 for i in range(1, 5) 93 call cursor(i, 1) 94 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 95 endfor 96 97 set listchars-=tab:<=> 98 set listchars+=tab:>- 99 set listchars+=trail:< 100 set nolist 101 normal ggdG 102 call append(0, [ 103 \ ' fff ', 104 \ ' gg ', 105 \ ' h ', 106 \ 'iii ', 107 \ ]) 108 let l = split(execute("%list"), "\n") 109 call assert_equal([ 110 \ '..fff>--<<$', 111 \ '>-------gg>-----$', 112 \ '.....h>-$', 113 \ 'iii<<<<><<$', '$'], l) 114 115 " Test lead and trail 116 normal ggdG 117 set listchars& 118 set listchars+=lead:>,trail:<,space:x 119 set list 120 121 call append(0, [ 122 \ ' ffff ', 123 \ ' gg', 124 \ 'h ', 125 \ ' ', 126 \ ' 0 0 ', 127 \ ]) 128 129 let expected = [ 130 \ '>>>>ffff<<<<$', 131 \ '>>>>>>>>>>gg$', 132 \ 'h<<<<<<<<<<<$', 133 \ '<<<<<<<<<<<<$', 134 \ '>>>>0xx0<<<<$', 135 \ '$' 136 \ ] 137 redraw! 138 for i in range(1, 5) 139 call cursor(i, 1) 140 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 141 endfor 142 143 call assert_equal(expected, split(execute("%list"), "\n")) 144 145 " Test multispace 146 normal ggdG 147 set listchars& 148 set listchars+=multispace:yYzZ 149 set list 150 151 call append(0, [ 152 \ ' ffff ', 153 \ ' i i gg', 154 \ ' h ', 155 \ ' j ', 156 \ ' 0 0 ', 157 \ ]) 158 159 let expected = [ 160 \ 'yYzZffffyYzZ$', 161 \ 'yYi iyYzZygg$', 162 \ ' hyYzZyYzZyY$', 163 \ 'yYzZyYzZyYj $', 164 \ 'yYzZ0yY0yYzZ$', 165 \ '$' 166 \ ] 167 redraw! 168 for i in range(1, 5) 169 call cursor(i, 1) 170 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 171 endfor 172 173 call assert_equal(expected, split(execute("%list"), "\n")) 174 175 " the last occurrence of 'multispace:' is used 176 set listchars+=space:x,multispace:XyY 177 178 let expected = [ 179 \ 'XyYXffffXyYX$', 180 \ 'XyixiXyYXygg$', 181 \ 'xhXyYXyYXyYX$', 182 \ 'XyYXyYXyYXjx$', 183 \ 'XyYX0Xy0XyYX$', 184 \ '$' 185 \ ] 186 redraw! 187 for i in range(1, 5) 188 call cursor(i, 1) 189 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 190 endfor 191 192 call assert_equal(expected, split(execute("%list"), "\n")) 193 194 set listchars+=lead:>,trail:< 195 196 let expected = [ 197 \ '>>>>ffff<<<<$', 198 \ '>>ixiXyYXygg$', 199 \ '>h<<<<<<<<<<$', 200 \ '>>>>>>>>>>j<$', 201 \ '>>>>0Xy0<<<<$', 202 \ '$' 203 \ ] 204 redraw! 205 for i in range(1, 5) 206 call cursor(i, 1) 207 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 208 endfor 209 210 call assert_equal(expected, split(execute("%list"), "\n")) 211 212 " removing 'multispace:' 213 set listchars-=multispace:XyY 214 set listchars-=multispace:yYzZ 215 216 let expected = [ 217 \ '>>>>ffff<<<<$', 218 \ '>>ixixxxxxgg$', 219 \ '>h<<<<<<<<<<$', 220 \ '>>>>>>>>>>j<$', 221 \ '>>>>0xx0<<<<$', 222 \ '$' 223 \ ] 224 redraw! 225 for i in range(1, 5) 226 call cursor(i, 1) 227 call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) 228 endfor 229 230 call assert_equal(expected, split(execute("%list"), "\n")) 231 232 " test nbsp 233 normal ggdG 234 set listchars=nbsp:X,trail:Y 235 set list 236 " Non-breaking space 237 let nbsp = nr2char(0xa0) 238 call append(0, [ ">" .. nbsp .. "<" ]) 239 240 let expected = '>X< ' 241 242 redraw! 243 call cursor(1, 1) 244 call assert_equal([expected], ScreenLines(1, virtcol('$'))) 245 246 set listchars=nbsp:X 247 redraw! 248 call cursor(1, 1) 249 call assert_equal([expected], ScreenLines(1, virtcol('$'))) 250 251 " test extends 252 normal ggdG 253 set listchars=extends:Z 254 set nowrap 255 set nolist 256 call append(0, [ repeat('A', &columns + 1) ]) 257 258 let expected = repeat('A', &columns) 259 260 redraw! 261 call cursor(1, 1) 262 call assert_equal([expected], ScreenLines(1, &columns)) 263 264 set list 265 let expected = expected[:-2] . 'Z' 266 redraw! 267 call cursor(1, 1) 268 call assert_equal([expected], ScreenLines(1, &columns)) 269 270 enew! 271 set listchars& ff& 272endfunc 273 274" Test that unicode listchars characters get properly inserted 275func Test_listchars_unicode() 276 enew! 277 let oldencoding=&encoding 278 set encoding=utf-8 279 set ff=unix 280 281 set listchars=eol:⇔,space:␣,multispace:≡≢≣,nbsp:≠,tab:←↔→ 282 set list 283 284 let nbsp = nr2char(0xa0) 285 call append(0, [" a\tb c" .. nbsp .. "d "]) 286 let expected = ['≡≢≣≡≢≣≡≢a←↔↔↔↔↔→b␣c≠d≡≢⇔'] 287 redraw! 288 call cursor(1, 1) 289 call assert_equal(expected, ScreenLines(1, virtcol('$'))) 290 291 set listchars=eol:\\u21d4,space:\\u2423,multispace:≡\\u2262\\U00002263,nbsp:\\U00002260,tab:←↔\\u2192 292 redraw! 293 call assert_equal(expected, ScreenLines(1, virtcol('$'))) 294 295 set listchars+=lead:⇨,trail:⇦ 296 let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔'] 297 redraw! 298 call cursor(1, 1) 299 call assert_equal(expected, ScreenLines(1, virtcol('$'))) 300 301 let &encoding=oldencoding 302 enew! 303 set listchars& ff& 304endfunction 305 306func Test_listchars_invalid() 307 enew! 308 set ff=unix 309 310 set listchars& 311 set list 312 set ambiwidth=double 313 314 " No colon 315 call assert_fails('set listchars=x', 'E474:') 316 call assert_fails('set listchars=x', 'E474:') 317 call assert_fails('set listchars=multispace', 'E474:') 318 319 " Too short 320 call assert_fails('set listchars=space:', 'E474:') 321 call assert_fails('set listchars=tab:x', 'E474:') 322 call assert_fails('set listchars=multispace:', 'E474:') 323 324 " One occurrence too short 325 call assert_fails('set listchars=space:,space:x', 'E474:') 326 call assert_fails('set listchars=space:x,space:', 'E474:') 327 call assert_fails('set listchars=tab:x,tab:xx', 'E474:') 328 call assert_fails('set listchars=tab:xx,tab:x', 'E474:') 329 call assert_fails('set listchars=multispace:,multispace:x', 'E474:') 330 call assert_fails('set listchars=multispace:x,multispace:', 'E474:') 331 332 " Too long 333 call assert_fails('set listchars=space:xx', 'E474:') 334 call assert_fails('set listchars=tab:xxxx', 'E474:') 335 336 " Has non-single width character 337 call assert_fails('set listchars=space:·', 'E474:') 338 call assert_fails('set listchars=tab:·x', 'E474:') 339 call assert_fails('set listchars=tab:x·', 'E474:') 340 call assert_fails('set listchars=tab:xx·', 'E474:') 341 call assert_fails('set listchars=multispace:·', 'E474:') 342 call assert_fails('set listchars=multispace:xxx·', 'E474:') 343 344 enew! 345 set ambiwidth& listchars& ff& 346endfunction 347 348" Tests that space characters following composing character won't get replaced 349" by listchars. 350func Test_listchars_composing() 351 enew! 352 let oldencoding=&encoding 353 set encoding=utf-8 354 set ff=unix 355 set list 356 357 set listchars=eol:$,space:_,nbsp:= 358 359 let nbsp1 = nr2char(0xa0) 360 let nbsp2 = nr2char(0x202f) 361 call append(0, [ 362 \ " \u3099\t \u309A" .. nbsp1 .. nbsp1 .. "\u0302" .. nbsp2 .. nbsp2 .. "\u0302", 363 \ ]) 364 let expected = [ 365 \ "_ \u3099^I \u309A=" .. nbsp1 .. "\u0302=" .. nbsp2 .. "\u0302$" 366 \ ] 367 redraw! 368 call cursor(1, 1) 369 call assert_equal(expected, ScreenLines(1, virtcol('$'))) 370 let &encoding=oldencoding 371 enew! 372 set listchars& ff& 373endfunction 374 375" Check for the value of the 'listchars' option 376func s:CheckListCharsValue(expected) 377 call assert_equal(a:expected, &listchars) 378 call assert_equal(a:expected, getwinvar(0, '&listchars')) 379endfunc 380 381" Test for using a window local value for 'listchars' 382func Test_listchars_window_local() 383 %bw! 384 set list listchars& 385 new 386 " set a local value for 'listchars' 387 setlocal listchars=tab:+-,eol:# 388 call s:CheckListCharsValue('tab:+-,eol:#') 389 " When local value is reset, global value should be used 390 setlocal listchars= 391 call s:CheckListCharsValue('eol:$') 392 " Use 'setlocal <' to copy global value 393 setlocal listchars=space:.,extends:> 394 setlocal listchars< 395 call s:CheckListCharsValue('eol:$') 396 " Use 'set <' to copy global value 397 setlocal listchars=space:.,extends:> 398 set listchars< 399 call s:CheckListCharsValue('eol:$') 400 " Changing global setting should not change the local setting 401 setlocal listchars=space:.,extends:> 402 setglobal listchars=tab:+-,eol:# 403 call s:CheckListCharsValue('space:.,extends:>') 404 " when split opening a new window, local value should be copied 405 split 406 call s:CheckListCharsValue('space:.,extends:>') 407 " clearing local value in one window should not change the other window 408 set listchars& 409 call s:CheckListCharsValue('eol:$') 410 close 411 call s:CheckListCharsValue('space:.,extends:>') 412 413 " use different values for 'listchars' items in two different windows 414 call setline(1, ["\t one two "]) 415 setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# 416 split 417 setlocal listchars=tab:[.],lead:#,space:_,trail:.,eol:& 418 split 419 set listchars=tab:+-+,lead:^,space:>,trail:<,eol:% 420 call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) 421 close 422 call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$'))) 423 close 424 call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) 425 " changing the global setting should not change the local value 426 setglobal listchars=tab:[.],lead:#,space:_,trail:.,eol:& 427 call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) 428 set listchars< 429 call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$'))) 430 431 " Using setglobal in a window with local setting should not affect the 432 " window. But should impact other windows using the global setting. 433 enew! | only 434 call setline(1, ["\t one two "]) 435 set listchars=tab:[.],lead:#,space:_,trail:.,eol:& 436 split 437 setlocal listchars=tab:+-+,lead:^,space:>,trail:<,eol:% 438 split 439 setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# 440 setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$ 441 call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) 442 close 443 call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) 444 close 445 call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$'))) 446 447 " Setting the global setting to the default value should not impact a window 448 " using a local setting. 449 split 450 setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# 451 setglobal listchars&vim 452 call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) 453 close 454 call assert_equal(['^I one two $'], ScreenLines(1, virtcol('$'))) 455 456 " Setting the local setting to the default value should not impact a window 457 " using a global setting. 458 set listchars=tab:{.},lead:-,space:=,trail:#,eol:$ 459 split 460 setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# 461 call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) 462 setlocal listchars&vim 463 call assert_equal(['^I one two $'], ScreenLines(1, virtcol('$'))) 464 close 465 call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$'))) 466 467 " Using set in a window with a local setting should change it to use the 468 " global setting and also impact other windows using the global setting. 469 split 470 setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# 471 call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) 472 set listchars=tab:+-+,lead:^,space:>,trail:<,eol:% 473 call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) 474 close 475 call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) 476 477 " Setting invalid value for a local setting should not impact the local and 478 " global settings. 479 split 480 setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# 481 let cmd = 'setlocal listchars=tab:{.},lead:-,space:=,trail:#,eol:$,x' 482 call assert_fails(cmd, 'E474:') 483 call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) 484 close 485 call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) 486 487 " Setting invalid value for a global setting should not impact the local and 488 " global settings. 489 split 490 setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# 491 let cmd = 'setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$,x' 492 call assert_fails(cmd, 'E474:') 493 call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) 494 close 495 call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) 496 497 " Closing window with local lcs-multispace should not cause a memory leak. 498 setlocal listchars=multispace:---+ 499 split 500 call s:CheckListCharsValue('multispace:---+') 501 close 502 503 %bw! 504 set list& listchars& 505endfunc 506 507func Test_listchars_foldcolumn() 508 CheckScreendump 509 510 let lines =<< trim END 511 call setline(1, ['aaa', '', 'a', 'aaaaaa']) 512 vsplit 513 vsplit 514 windo set signcolumn=yes foldcolumn=1 winminwidth=0 nowrap list listchars=extends:>,precedes:< 515 END 516 call writefile(lines, 'XTest_listchars') 517 518 let buf = RunVimInTerminal('-S XTest_listchars', {'rows': 10, 'cols': 60}) 519 520 call term_sendkeys(buf, "13\<C-W>>") 521 call VerifyScreenDump(buf, 'Test_listchars_01', {}) 522 call term_sendkeys(buf, "\<C-W>>") 523 call VerifyScreenDump(buf, 'Test_listchars_02', {}) 524 call term_sendkeys(buf, "\<C-W>>") 525 call VerifyScreenDump(buf, 'Test_listchars_03', {}) 526 call term_sendkeys(buf, "\<C-W>>") 527 call VerifyScreenDump(buf, 'Test_listchars_04', {}) 528 call term_sendkeys(buf, "\<C-W>>") 529 call VerifyScreenDump(buf, 'Test_listchars_05', {}) 530 call term_sendkeys(buf, "\<C-W>h") 531 call term_sendkeys(buf, ":set nowrap foldcolumn=4\<CR>") 532 call term_sendkeys(buf, "15\<C-W><") 533 call VerifyScreenDump(buf, 'Test_listchars_06', {}) 534 call term_sendkeys(buf, "4\<C-W><") 535 call VerifyScreenDump(buf, 'Test_listchars_07', {}) 536 537 " clean up 538 call StopVimInTerminal(buf) 539 call delete('XTest_listchars') 540endfunc 541 542 543" vim: shiftwidth=2 sts=2 expandtab 544