bufhl_spec.lua (32207B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 local Screen = require('test.functional.ui.screen') 4 5 local clear, feed, insert = n.clear, n.feed, n.insert 6 local command, neq = n.command, t.neq 7 local api = n.api 8 local eq = t.eq 9 local pcall_err = t.pcall_err 10 local set_virtual_text = api.nvim_buf_set_virtual_text 11 12 describe('Buffer highlighting', function() 13 local screen 14 15 before_each(function() 16 clear() 17 command('syntax on') 18 screen = Screen.new(40, 8) 19 screen:set_default_attr_ids({ 20 [1] = { bold = true, foreground = Screen.colors.Blue }, 21 [2] = { foreground = Screen.colors.Fuchsia }, -- String 22 [3] = { foreground = Screen.colors.Brown, bold = true }, -- Statement 23 [4] = { foreground = Screen.colors.SlateBlue }, -- Special 24 [5] = { bold = true, foreground = Screen.colors.SlateBlue }, 25 [6] = { foreground = Screen.colors.DarkCyan }, -- Identifier 26 [7] = { bold = true }, 27 [8] = { underline = true, bold = true, foreground = Screen.colors.SlateBlue }, 28 [9] = { foreground = Screen.colors.SlateBlue, underline = true }, 29 [10] = { foreground = Screen.colors.Red }, 30 [11] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, 31 [12] = { foreground = Screen.colors.Blue1 }, 32 [13] = { foreground = Screen.colors.Black, background = Screen.colors.LightGrey }, 33 [14] = { background = Screen.colors.Gray90 }, 34 [15] = { background = Screen.colors.Gray90, bold = true, foreground = Screen.colors.Brown }, 35 [16] = { foreground = Screen.colors.Magenta, background = Screen.colors.Gray90 }, 36 [17] = { foreground = Screen.colors.Magenta, background = Screen.colors.LightRed }, 37 [18] = { background = Screen.colors.LightRed }, 38 [19] = { foreground = Screen.colors.Blue1, background = Screen.colors.LightRed }, 39 [20] = { underline = true, bold = true, foreground = Screen.colors.Cyan4 }, 40 }) 41 end) 42 43 local add_highlight = api.nvim_buf_add_highlight 44 local clear_namespace = api.nvim_buf_clear_namespace 45 46 it('works', function() 47 insert([[ 48 these are some lines 49 with colorful text]]) 50 feed('+') 51 52 screen:expect([[ 53 these are some lines | 54 with colorful tex^t | 55 {1:~ }|*5 56 | 57 ]]) 58 59 add_highlight(0, -1, 'String', 0, 10, 14) 60 add_highlight(0, -1, 'Statement', 1, 5, -1) 61 62 screen:expect([[ 63 these are {2:some} lines | 64 with {3:colorful tex^t} | 65 {1:~ }|*5 66 | 67 ]]) 68 69 feed('ggo<esc>') 70 screen:expect([[ 71 these are {2:some} lines | 72 ^ | 73 with {3:colorful text} | 74 {1:~ }|*4 75 | 76 ]]) 77 78 clear_namespace(0, -1, 0, -1) 79 screen:expect([[ 80 these are some lines | 81 ^ | 82 with colorful text | 83 {1:~ }|*4 84 | 85 ]]) 86 end) 87 88 describe('support using multiple namespaces', function() 89 local id1, id2 90 before_each(function() 91 insert([[ 92 a longer example 93 in order to demonstrate 94 combining highlights 95 from different sources]]) 96 97 command('hi ImportantWord gui=bold cterm=bold') 98 id1 = add_highlight(0, 0, 'ImportantWord', 0, 2, 8) 99 add_highlight(0, id1, 'ImportantWord', 1, 12, -1) 100 add_highlight(0, id1, 'ImportantWord', 2, 0, 9) 101 add_highlight(0, id1, 'ImportantWord', 3, 5, 14) 102 103 -- add_highlight can be called like this to get a new source 104 -- without adding any highlight 105 id2 = add_highlight(0, 0, '', 0, 0, 0) 106 neq(id1, id2) 107 108 add_highlight(0, id2, 'Special', 0, 2, 8) 109 add_highlight(0, id2, 'Identifier', 1, 3, 8) 110 add_highlight(0, id2, 'Special', 1, 14, 20) 111 add_highlight(0, id2, 'Underlined', 2, 6, 12) 112 add_highlight(0, id2, 'Underlined', 3, 0, 9) 113 114 screen:expect([[ 115 a {5:longer} example | 116 in {6:order} to {7:de}{5:monstr}{7:ate} | 117 {7:combin}{8:ing}{9: hi}ghlights | 118 {9:from }{8:diff}{7:erent} source^s | 119 {1:~ }|*3 120 | 121 ]]) 122 end) 123 124 it('and clearing the first added', function() 125 clear_namespace(0, id1, 0, -1) 126 screen:expect([[ 127 a {4:longer} example | 128 in {6:order} to de{4:monstr}ate | 129 combin{9:ing hi}ghlights | 130 {9:from diff}erent source^s | 131 {1:~ }|*3 132 | 133 ]]) 134 end) 135 136 it('and clearing using deprecated name', function() 137 api.nvim_buf_clear_highlight(0, id1, 0, -1) 138 screen:expect([[ 139 a {4:longer} example | 140 in {6:order} to de{4:monstr}ate | 141 combin{9:ing hi}ghlights | 142 {9:from diff}erent source^s | 143 {1:~ }|*3 144 | 145 ]]) 146 end) 147 148 it('and clearing the second added', function() 149 clear_namespace(0, id2, 0, -1) 150 screen:expect([[ 151 a {7:longer} example | 152 in order to {7:demonstrate} | 153 {7:combining} highlights | 154 from {7:different} source^s | 155 {1:~ }|*3 156 | 157 ]]) 158 end) 159 160 it('and clearing line ranges', function() 161 clear_namespace(0, -1, 0, 1) 162 clear_namespace(0, id1, 1, 2) 163 clear_namespace(0, id2, 2, -1) 164 screen:expect([[ 165 a longer example | 166 in {6:order} to de{4:monstr}ate | 167 {7:combining} highlights | 168 from {7:different} source^s | 169 {1:~ }|*3 170 | 171 ]]) 172 end) 173 174 it('and renumbering lines', function() 175 feed('3Gddggo<esc>') 176 screen:expect([[ 177 a {5:longer} example | 178 ^ | 179 in {6:order} to {7:de}{5:monstr}{7:ate} | 180 {9:from }{8:diff}{7:erent} sources | 181 {1:~ }|*3 182 | 183 ]]) 184 185 -- TODO(bfedl): this behaves a bit weirdly due to the highlight on 186 -- the deleted line wrapping around. we should invalidate 187 -- highlights when they are completely inside deleted text 188 command('3move 4') 189 screen:expect { 190 grid = [[ 191 a {5:longer} example | 192 | 193 {8:from different sources} | 194 {8:^in }{20:order}{8: to demonstrate} | 195 {1:~ }|*3 196 | 197 ]], 198 } 199 --screen:expect([[ 200 -- a {5:longer} example | 201 -- | 202 -- {9:from }{8:diff}{7:erent} sources | 203 -- ^in {6:order} to {7:de}{5:monstr}{7:ate} | 204 -- {1:~ }|*3 205 -- | 206 --]]) 207 208 command('undo') 209 screen:expect { 210 grid = [[ 211 a {5:longer} example | 212 ^ | 213 in {6:order} to {7:de}{5:monstr}{7:ate} | 214 {9:from }{8:diff}{7:erent} sources | 215 {1:~ }|*3 216 1 change; before #4 {MATCH:.*}| 217 ]], 218 } 219 220 command('undo') 221 screen:expect { 222 grid = [[ 223 ^a {5:longer} example | 224 in {6:order} to {7:de}{5:monstr}{7:ate} | 225 {9:from }{8:diff}{7:erent} sources | 226 {1:~ }|*4 227 1 line less; before #3 {MATCH:.*}| 228 ]], 229 } 230 231 command('undo') 232 screen:expect { 233 grid = [[ 234 a {5:longer} example | 235 in {6:order} to {7:de}{5:monstr}{7:ate} | 236 {7:^combin}{8:ing}{9: hi}ghlights | 237 {9:from }{8:diff}{7:erent} sources | 238 {1:~ }|*3 239 1 more line; before #2 {MATCH:.*}| 240 ]], 241 } 242 end) 243 244 it('and moving lines around', function() 245 command('2move 3') 246 screen:expect { 247 grid = [[ 248 a {5:longer} example | 249 {7:combin}{8:ing}{9: hi}ghlights | 250 ^in {6:order} to {7:de}{5:monstr}{7:ate} | 251 {9:from }{8:diff}{7:erent} sources | 252 {1:~ }|*3 253 | 254 ]], 255 } 256 257 command('1,2move 4') 258 screen:expect { 259 grid = [[ 260 in {6:order} to {7:de}{5:monstr}{7:ate} | 261 {9:from }{8:diff}{7:erent} sources | 262 a {5:longer} example | 263 {7:^combin}{8:ing}{9: hi}ghlights | 264 {1:~ }|*3 265 | 266 ]], 267 } 268 269 command('undo') 270 screen:expect { 271 grid = [[ 272 a {5:longer} example | 273 {7:combin}{8:ing}{9: hi}ghlights | 274 ^in {6:order} to {7:de}{5:monstr}{7:ate} | 275 {9:from }{8:diff}{7:erent} sources | 276 {1:~ }|*3 277 2 changes; before #3 {MATCH:.*}| 278 ]], 279 } 280 281 command('undo') 282 screen:expect { 283 grid = [[ 284 a {5:longer} example | 285 in {6:order} to {7:de}{5:monstr}{7:ate} | 286 {7:combin}{8:ing}{9: hi}ghlights | 287 {9:from }{8:diff}{7:erent} source^s | 288 {1:~ }|*3 289 1 change; before #2 {MATCH:.*}| 290 ]], 291 } 292 end) 293 294 it('and adjusting columns', function() 295 -- insert before 296 feed('ggiquite <esc>') 297 screen:expect { 298 grid = [[ 299 quite^ a {5:longer} example | 300 in {6:order} to {7:de}{5:monstr}{7:ate} | 301 {7:combin}{8:ing}{9: hi}ghlights | 302 {9:from }{8:diff}{7:erent} sources | 303 {1:~ }|*3 304 | 305 ]], 306 } 307 308 feed('u') 309 screen:expect { 310 grid = [[ 311 ^a {5:longer} example | 312 in {6:order} to {7:de}{5:monstr}{7:ate} | 313 {7:combin}{8:ing}{9: hi}ghlights | 314 {9:from }{8:diff}{7:erent} sources | 315 {1:~ }|*3 316 1 change; before #2 {MATCH:.*}| 317 ]], 318 } 319 320 -- change/insert in the middle 321 feed('+fesAAAA') 322 screen:expect { 323 grid = [[ 324 a {5:longer} example | 325 in {6:ordAAAA^r} to {7:de}{5:monstr}{7:ate} | 326 {7:combin}{8:ing}{9: hi}ghlights | 327 {9:from }{8:diff}{7:erent} sources | 328 {1:~ }|*3 329 {7:-- INSERT --} | 330 ]], 331 } 332 333 feed('<esc>tdD') 334 screen:expect { 335 grid = [[ 336 a {5:longer} example | 337 in {6:ordAAAAr} t^o | 338 {7:combin}{8:ing}{9: hi}ghlights | 339 {9:from }{8:diff}{7:erent} sources | 340 {1:~ }|*3 341 | 342 ]], 343 } 344 345 feed('u') 346 screen:expect { 347 grid = [[ 348 a {5:longer} example | 349 in {6:ordAAAAr} to^ {7:de}{5:monstr}{7:ate} | 350 {7:combin}{8:ing}{9: hi}ghlights | 351 {9:from }{8:diff}{7:erent} sources | 352 {1:~ }|*3 353 1 change; before #4 {MATCH:.*}| 354 ]], 355 } 356 357 feed('u') 358 screen:expect { 359 grid = [[ 360 a {5:longer} example | 361 in {6:ord^er} to {7:de}{5:monstr}{7:ate} | 362 {7:combin}{8:ing}{9: hi}ghlights | 363 {9:from }{8:diff}{7:erent} sources | 364 {1:~ }|*3 365 1 change; before #3 {MATCH:.*}| 366 ]], 367 } 368 end) 369 370 it('and joining lines', function() 371 feed('ggJJJ') 372 screen:expect { 373 grid = [[ 374 a {5:longer} example in {6:order} to {7:de}{5:monstr}{7:ate}| 375 {7:combin}{8:ing}{9: hi}ghlights^ {9:from }{8:diff}{7:erent} sou| 376 rces | 377 {1:~ }|*4 378 | 379 ]], 380 } 381 382 feed('uuu') 383 screen:expect { 384 grid = [[ 385 ^a {5:longer} example | 386 in {6:order} to {7:de}{5:monstr}{7:ate} | 387 {7:combin}{8:ing}{9: hi}ghlights | 388 {9:from }{8:diff}{7:erent} sources | 389 {1:~ }|*3 390 1 more line; before #2 {MATCH:.*}| 391 ]], 392 } 393 end) 394 395 it('and splitting lines', function() 396 feed('2Gtti<cr>') 397 screen:expect { 398 grid = [[ 399 a {5:longer} example | 400 in {6:order} | 401 ^ to {7:de}{5:monstr}{7:ate} | 402 {7:combin}{8:ing}{9: hi}ghlights | 403 {9:from }{8:diff}{7:erent} sources | 404 {1:~ }|*2 405 {7:-- INSERT --} | 406 ]], 407 } 408 409 feed('<esc>tsi<cr>') 410 screen:expect { 411 grid = [[ 412 a {5:longer} example | 413 in {6:order} | 414 to {7:de}{5:mo} | 415 {5:^nstr}{7:ate} | 416 {7:combin}{8:ing}{9: hi}ghlights | 417 {9:from }{8:diff}{7:erent} sources | 418 {1:~ }| 419 {7:-- INSERT --} | 420 ]], 421 } 422 423 feed('<esc>u') 424 screen:expect { 425 grid = [[ 426 a {5:longer} example | 427 in {6:order} | 428 to {7:de}{5:mo^nstr}{7:ate} | 429 {7:combin}{8:ing}{9: hi}ghlights | 430 {9:from }{8:diff}{7:erent} sources | 431 {1:~ }|*2 432 1 line less; before #3 {MATCH:.*}| 433 ]], 434 } 435 436 feed('<esc>u') 437 screen:expect { 438 grid = [[ 439 a {5:longer} example | 440 in {6:order}^ to {7:de}{5:monstr}{7:ate} | 441 {7:combin}{8:ing}{9: hi}ghlights | 442 {9:from }{8:diff}{7:erent} sources | 443 {1:~ }|*3 444 1 line less; before #2 {MATCH:.*}| 445 ]], 446 } 447 end) 448 end) 449 450 pending('prioritizes latest added highlight', function() 451 insert([[ 452 three overlapping colors]]) 453 add_highlight(0, 0, 'Identifier', 0, 6, 17) 454 add_highlight(0, 0, 'String', 0, 14, 23) 455 local id = add_highlight(0, 0, 'Special', 0, 0, 9) 456 457 screen:expect([[ 458 {4:three ove}{6:rlapp}{2:ing color}^s | 459 {1:~ }|*6 460 | 461 ]]) 462 463 clear_namespace(0, id, 0, 1) 464 screen:expect([[ 465 three {6:overlapp}{2:ing color}^s | 466 {1:~ }|*6 467 | 468 ]]) 469 end) 470 471 it('prioritizes earlier highlight groups (TEMP)', function() 472 insert([[ 473 three overlapping colors]]) 474 add_highlight(0, 0, 'Identifier', 0, 6, 17) 475 add_highlight(0, 0, 'String', 0, 14, 23) 476 local id = add_highlight(0, 0, 'Special', 0, 0, 9) 477 478 screen:expect { 479 grid = [[ 480 {4:three }{6:overlapp}{2:ing color}^s | 481 {1:~ }|*6 482 | 483 ]], 484 } 485 486 clear_namespace(0, id, 0, 1) 487 screen:expect { 488 grid = [[ 489 three {6:overlapp}{2:ing color}^s | 490 {1:~ }|*6 491 | 492 ]], 493 } 494 end) 495 496 it('respects priority', function() 497 local id = api.nvim_create_namespace('') 498 insert [[foobar]] 499 500 api.nvim_buf_set_extmark(0, id, 0, 0, { 501 end_line = 0, 502 end_col = 5, 503 hl_group = 'Statement', 504 priority = 100, 505 }) 506 api.nvim_buf_set_extmark(0, id, 0, 0, { 507 end_line = 0, 508 end_col = 6, 509 hl_group = 'String', 510 priority = 1, 511 }) 512 513 screen:expect [[ 514 {3:fooba}{2:^r} | 515 {1:~ }|*6 516 | 517 ]] 518 519 clear_namespace(0, id, 0, -1) 520 screen:expect { 521 grid = [[ 522 fooba^r | 523 {1:~ }|*6 524 | 525 ]], 526 } 527 528 api.nvim_buf_set_extmark(0, id, 0, 0, { 529 end_line = 0, 530 end_col = 6, 531 hl_group = 'String', 532 priority = 1, 533 }) 534 api.nvim_buf_set_extmark(0, id, 0, 0, { 535 end_line = 0, 536 end_col = 5, 537 hl_group = 'Statement', 538 priority = 100, 539 }) 540 541 screen:expect [[ 542 {3:fooba}{2:^r} | 543 {1:~ }|*6 544 | 545 ]] 546 end) 547 548 it('works with multibyte text', function() 549 insert([[ 550 Ta båten över sjön!]]) 551 add_highlight(0, -1, 'Identifier', 0, 3, 9) 552 add_highlight(0, -1, 'String', 0, 16, 21) 553 554 screen:expect([[ 555 Ta {6:båten} över {2:sjön}^! | 556 {1:~ }|*6 557 | 558 ]]) 559 end) 560 561 it('works with new syntax groups', function() 562 insert([[ 563 fancy code in a new fancy language]]) 564 add_highlight(0, -1, 'FancyLangItem', 0, 0, 5) 565 screen:expect([[ 566 fancy code in a new fancy languag^e | 567 {1:~ }|*6 568 | 569 ]]) 570 571 command('hi FancyLangItem guifg=red') 572 screen:expect([[ 573 {10:fancy} code in a new fancy languag^e | 574 {1:~ }|*6 575 | 576 ]]) 577 end) 578 579 describe('virtual text decorations', function() 580 local id1, id2 ---@type integer, integer 581 before_each(function() 582 insert([[ 583 1 + 2 584 3 + 585 x = 4]]) 586 feed('O<esc>20A5, <esc>gg') 587 screen:expect([[ 588 ^1 + 2 | 589 3 + | 590 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 591 , 5, 5, 5, 5, 5, 5, | 592 x = 4 | 593 {1:~ }|*2 594 | 595 ]]) 596 597 id1 = set_virtual_text(0, 0, 0, { { '=', 'Statement' }, { ' 3', 'Number' } }, {}) 598 set_virtual_text(0, id1, 1, { { 'ERROR:', 'ErrorMsg' }, { ' invalid syntax' } }, {}) 599 id2 = set_virtual_text(0, 0, 2, { 600 { 601 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 602 }, 603 }, {}) 604 neq(id2, id1) 605 end) 606 607 it('works', function() 608 screen:expect([[ 609 ^1 + 2 {3:=}{2: 3} | 610 3 + {11:ERROR:} invalid syntax | 611 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 612 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 613 x = 4 | 614 {1:~ }|*2 615 | 616 ]]) 617 618 clear_namespace(0, id1, 0, -1) 619 screen:expect([[ 620 ^1 + 2 | 621 3 + | 622 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 623 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 624 x = 4 | 625 {1:~ }|*2 626 | 627 ]]) 628 629 -- Handles doublewidth chars, leaving a space if truncating 630 -- in the middle of a char 631 eq( 632 -1, 633 set_virtual_text( 634 0, 635 -1, 636 1, 637 { { '暗x事zz速野谷質結育副住新覚丸活解終事', 'Comment' } }, 638 {} 639 ) 640 ) 641 screen:expect([[ 642 ^1 + 2 | 643 3 + {12:暗x事zz速野谷質結育副住新覚丸活解終 }| 644 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 645 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 646 x = 4 | 647 {1:~ }|*2 648 | 649 ]]) 650 651 feed('2Gx') 652 screen:expect([[ 653 1 + 2 | 654 ^ + {12:暗x事zz速野谷質結育副住新覚丸活解終事}| 655 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 656 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 657 x = 4 | 658 {1:~ }|*2 659 | 660 ]]) 661 662 feed('2Gdd') 663 -- TODO(bfredl): currently decorations get moved from a deleted line 664 -- to the next one. We might want to add "invalidation" when deleting 665 -- over a decoration. 666 screen:expect { 667 grid = [[ 668 1 + 2 | 669 ^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 670 , 5, 5, 5, 5, 5, 5, {12:暗x事zz速野谷質結育}| 671 x = 4 | 672 {1:~ }|*3 673 | 674 ]], 675 } 676 --screen:expect([[ 677 -- 1 + 2 | 678 -- ^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 679 -- , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 680 -- x = 4 | 681 -- {1:~ }|*3 682 -- | 683 --]]) 684 end) 685 686 it('validates contents', function() 687 -- this used to leak memory 688 eq( 689 "Invalid 'chunk': expected Array, got String", 690 pcall_err(set_virtual_text, 0, id1, 0, { 'texty' }, {}) 691 ) 692 eq( 693 "Invalid 'chunk': expected Array, got String", 694 pcall_err(set_virtual_text, 0, id1, 0, { { 'very' }, 'texty' }, {}) 695 ) 696 end) 697 698 it('can be retrieved', function() 699 local get_extmarks = api.nvim_buf_get_extmarks 700 local line_count = api.nvim_buf_line_count 701 702 local s1 = { { 'Köttbullar', 'Comment' }, { 'Kräuterbutter' } } 703 local s2 = { { 'こんにちは', 'Comment' } } 704 705 set_virtual_text(0, id1, 0, s1, {}) 706 eq({ 707 { 708 1, 709 0, 710 0, 711 { 712 ns_id = id1, 713 priority = 0, 714 virt_text = s1, 715 -- other details 716 right_gravity = true, 717 virt_text_repeat_linebreak = false, 718 virt_text_pos = 'eol', 719 virt_text_hide = false, 720 }, 721 }, 722 }, get_extmarks(0, id1, { 0, 0 }, { 0, -1 }, { details = true })) 723 724 local lastline = line_count(0) 725 set_virtual_text(0, id1, line_count(0), s2, {}) 726 eq({ 727 { 728 3, 729 lastline, 730 0, 731 { 732 ns_id = id1, 733 priority = 0, 734 virt_text = s2, 735 -- other details 736 right_gravity = true, 737 virt_text_repeat_linebreak = false, 738 virt_text_pos = 'eol', 739 virt_text_hide = false, 740 }, 741 }, 742 }, get_extmarks(0, id1, { lastline, 0 }, { lastline, -1 }, { details = true })) 743 744 eq({}, get_extmarks(0, id1, { lastline + 9000, 0 }, { lastline + 9000, -1 }, {})) 745 end) 746 747 it('is not highlighted by visual selection', function() 748 feed('ggVG') 749 screen:expect([[ 750 {13:1 + 2} {3:=}{2: 3} | 751 {13:3 +} {11:ERROR:} invalid syntax | 752 {13:5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}| 753 {13:, 5, 5, 5, 5, 5, 5, } Lorem ipsum dolor s| 754 ^x{13: = 4} | 755 {1:~ }|*2 756 {7:-- VISUAL LINE --} | 757 ]]) 758 759 feed('<esc>') 760 screen:expect([[ 761 1 + 2 {3:=}{2: 3} | 762 3 + {11:ERROR:} invalid syntax | 763 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 764 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 765 ^x = 4 | 766 {1:~ }|*2 767 | 768 ]]) 769 770 -- special case: empty line has extra eol highlight 771 feed('ggd$') 772 screen:expect([[ 773 ^ {3:=}{2: 3} | 774 3 + {11:ERROR:} invalid syntax | 775 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 776 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 777 x = 4 | 778 {1:~ }|*2 779 | 780 ]]) 781 782 feed('jvk') 783 screen:expect([[ 784 ^ {3:=}{2: 3} | 785 {13:3} + {11:ERROR:} invalid syntax | 786 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 787 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 788 x = 4 | 789 {1:~ }|*2 790 {7:-- VISUAL --} | 791 ]]) 792 793 feed('o') 794 screen:expect([[ 795 {13: }{3:=}{2: 3} | 796 ^3 + {11:ERROR:} invalid syntax | 797 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 798 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 799 x = 4 | 800 {1:~ }|*2 801 {7:-- VISUAL --} | 802 ]]) 803 end) 804 805 it('works with listchars', function() 806 command('set list listchars+=eol:$') 807 screen:expect([[ 808 ^1 + 2{1:$}{3:=}{2: 3} | 809 3 +{1:$}{11:ERROR:} invalid syntax | 810 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 811 , 5, 5, 5, 5, 5, 5,{1:-$}Lorem ipsum dolor s| 812 x = 4{1:$} | 813 {1:~ }|*2 814 | 815 ]]) 816 817 clear_namespace(0, -1, 0, -1) 818 screen:expect([[ 819 ^1 + 2{1:$} | 820 3 +{1:$} | 821 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 822 , 5, 5, 5, 5, 5, 5,{1:-$} | 823 x = 4{1:$} | 824 {1:~ }|*2 825 | 826 ]]) 827 end) 828 829 it('works with cursorline', function() 830 command('set cursorline') 831 832 screen:expect { 833 grid = [[ 834 {14:^1 + 2 }{3:=}{2: 3}{14: }| 835 3 + {11:ERROR:} invalid syntax | 836 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 837 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 838 x = 4 | 839 {1:~ }|*2 840 | 841 ]], 842 } 843 844 feed('j') 845 screen:expect { 846 grid = [[ 847 1 + 2 {3:=}{2: 3} | 848 {14:^3 + }{11:ERROR:} invalid syntax{14: }| 849 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 850 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 851 x = 4 | 852 {1:~ }|*2 853 | 854 ]], 855 } 856 857 feed('j') 858 screen:expect { 859 grid = [[ 860 1 + 2 {3:=}{2: 3} | 861 3 + {11:ERROR:} invalid syntax | 862 {14:^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}| 863 {14:, 5, 5, 5, 5, 5, 5, }Lorem ipsum dolor s| 864 x = 4 | 865 {1:~ }|*2 866 | 867 ]], 868 } 869 end) 870 871 it('works with color column', function() 872 eq(-1, set_virtual_text(0, -1, 3, { { '暗x事', 'Comment' } }, {})) 873 screen:expect { 874 grid = [[ 875 ^1 + 2 {3:=}{2: 3} | 876 3 + {11:ERROR:} invalid syntax | 877 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 878 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 879 x = 4 {12:暗x事} | 880 {1:~ }|*2 881 | 882 ]], 883 } 884 885 command('set colorcolumn=9') 886 screen:expect { 887 grid = [[ 888 ^1 + 2 {3:=}{2: 3} | 889 3 + {11:ERROR:} invalid syntax | 890 5, 5, 5,{18: }5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| 891 , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| 892 x = 4 {12:暗x事} | 893 {1:~ }|*2 894 | 895 ]], 896 } 897 end) 898 end) 899 900 it('and virtual text use the same namespace counter', function() 901 local base = vim.iter(api.nvim_get_namespaces()):fold(0, function(acc, _, v) 902 return math.max(acc, v) 903 end) 904 905 eq(base + 1, add_highlight(0, 0, 'String', 0, 0, -1)) 906 eq(base + 2, set_virtual_text(0, 0, 0, { { '= text', 'Comment' } }, {})) 907 eq(base + 3, api.nvim_create_namespace('my-ns')) 908 eq(base + 4, add_highlight(0, 0, 'String', 0, 0, -1)) 909 eq(base + 5, set_virtual_text(0, 0, 0, { { '= text', 'Comment' } }, {})) 910 eq(base + 6, api.nvim_create_namespace('other-ns')) 911 end) 912 end)