decorations_spec.lua (320557B)
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 = n.clear 6 local feed = n.feed 7 local insert = n.insert 8 local exec_lua = n.exec_lua 9 local exec = n.exec 10 local expect_events = t.expect_events 11 local api = n.api 12 local fn = n.fn 13 local command = n.command 14 local eq = t.eq 15 local assert_alive = n.assert_alive 16 local pcall_err = t.pcall_err 17 18 --- @return integer 19 local function setup_provider(code) 20 return exec_lua([[ 21 local api = vim.api 22 _G.ns1 = api.nvim_create_namespace "ns1" 23 ]] .. (code or [[ 24 beamtrace = {} 25 local function on_do(kind, ...) 26 table.insert(beamtrace, {kind, ...}) 27 end 28 ]]) .. [[ 29 api.nvim_set_decoration_provider(_G.ns1, { 30 on_start = on_do; on_buf = on_do; 31 on_win = on_do; on_line = on_do; on_range = on_do; 32 on_end = on_do; _on_spell_nav = on_do; 33 }) 34 return _G.ns1 35 ]]) 36 end 37 38 local function setup_screen(screen) 39 screen:set_default_attr_ids { 40 [1] = { bold = true, foreground = Screen.colors.Blue }, 41 [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, 42 [3] = { foreground = Screen.colors.Brown }, 43 [4] = { foreground = Screen.colors.Blue1 }, 44 [5] = { foreground = Screen.colors.Magenta }, 45 [6] = { bold = true, foreground = Screen.colors.Brown }, 46 [7] = { background = Screen.colors.Gray90 }, 47 [8] = { bold = true, reverse = true }, 48 [9] = { reverse = true }, 49 [10] = { italic = true, background = Screen.colors.Magenta }, 50 [11] = { foreground = Screen.colors.Red, background = tonumber('0x005028') }, 51 [12] = { foreground = tonumber('0x990000') }, 52 [13] = { background = Screen.colors.LightBlue }, 53 [14] = { background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue }, 54 [15] = { special = Screen.colors.Blue, undercurl = true }, 55 [16] = { special = Screen.colors.Red, undercurl = true }, 56 [17] = { foreground = Screen.colors.Red }, 57 [18] = { bold = true, foreground = Screen.colors.SeaGreen }, 58 [19] = { bold = true }, 59 } 60 end 61 62 describe('decorations providers', function() 63 local screen ---@type test.functional.ui.screen 64 before_each(function() 65 clear() 66 screen = Screen.new(40, 8) 67 setup_screen(screen) 68 end) 69 70 local mulholland = [[ 71 // just to see if there was an accident 72 // on Mulholland Drive 73 try_start(); 74 bufref_T save_buf; 75 switch_buffer(&save_buf, buf); 76 posp = getmark(mark, false); 77 restore_buffer(&save_buf); ]] 78 79 local function check_trace(expected) 80 local actual = exec_lua [[ local b = beamtrace beamtrace = {} return b ]] 81 expect_events(expected, actual, 'beam trace') 82 end 83 84 it('does not OOM when inserting, rather than appending, to the decoration provider vector', function() 85 -- Add a dummy decoration provider with a larger ns id than what setup_provider() creates. 86 -- This forces get_decor_provider() to insert into the providers vector, 87 -- rather than append, which used to spin in an infinite loop allocating 88 -- memory until nvim crashed/was killed. 89 setup_provider([[ 90 local ns2 = api.nvim_create_namespace "ns2" 91 api.nvim_set_decoration_provider(ns2, {}) 92 ]]) 93 assert_alive() 94 end) 95 96 it('leave a trace', function() 97 insert(mulholland) 98 99 setup_provider() 100 101 screen:expect { 102 grid = [[ 103 // just to see if there was an accident | 104 // on Mulholland Drive | 105 try_start(); | 106 bufref_T save_buf; | 107 switch_buffer(&save_buf, buf); | 108 posp = getmark(mark, false); | 109 restore_buffer(&save_buf);^ | 110 | 111 ]], 112 } 113 check_trace { 114 { 'start', 4 }, 115 { 'win', 1000, 1, 0, 6 }, 116 { 'line', 1000, 1, 0 }, 117 { 'range', 1000, 1, 0, 0, 1, 0 }, 118 { 'line', 1000, 1, 1 }, 119 { 'range', 1000, 1, 1, 0, 2, 0 }, 120 { 'line', 1000, 1, 2 }, 121 { 'range', 1000, 1, 2, 0, 3, 0 }, 122 { 'line', 1000, 1, 3 }, 123 { 'range', 1000, 1, 3, 0, 4, 0 }, 124 { 'line', 1000, 1, 4 }, 125 { 'range', 1000, 1, 4, 0, 5, 0 }, 126 { 'line', 1000, 1, 5 }, 127 { 'range', 1000, 1, 5, 0, 6, 0 }, 128 { 'line', 1000, 1, 6 }, 129 { 'range', 1000, 1, 6, 0, 7, 0 }, 130 { 'end', 4 }, 131 } 132 133 feed 'iü<esc>' 134 screen:expect { 135 grid = [[ 136 // just to see if there was an accident | 137 // on Mulholland Drive | 138 try_start(); | 139 bufref_T save_buf; | 140 switch_buffer(&save_buf, buf); | 141 posp = getmark(mark, false); | 142 restore_buffer(&save_buf);^ü | 143 | 144 ]], 145 } 146 check_trace { 147 { 'start', 5 }, 148 { 'buf', 1, 5 }, 149 { 'win', 1000, 1, 0, 6 }, 150 { 'line', 1000, 1, 6 }, 151 { 'range', 1000, 1, 6, 0, 7, 0 }, 152 { 'end', 5 }, 153 } 154 end) 155 156 it('can have single provider', function() 157 insert(mulholland) 158 setup_provider [[ 159 local hl = api.nvim_get_hl_id_by_name "ErrorMsg" 160 local test_ns = api.nvim_create_namespace "mulholland" 161 function on_do(event, ...) 162 if event == "line" then 163 local win, buf, line = ... 164 api.nvim_buf_set_extmark(buf, test_ns, line, line, 165 { end_line = line, end_col = line+1, 166 hl_group = hl, 167 ephemeral = true 168 }) 169 end 170 end 171 ]] 172 173 screen:expect { 174 grid = [[ 175 {2:/}/ just to see if there was an accident | 176 /{2:/} on Mulholland Drive | 177 tr{2:y}_start(); | 178 buf{2:r}ef_T save_buf; | 179 swit{2:c}h_buffer(&save_buf, buf); | 180 posp {2:=} getmark(mark, false); | 181 restor{2:e}_buffer(&save_buf);^ | 182 | 183 ]], 184 } 185 end) 186 187 it('can indicate spellchecked points', function() 188 exec [[ 189 set spell 190 set spelloptions=noplainbuffer 191 syntax off 192 ]] 193 194 insert [[ 195 I am well written text. 196 i am not capitalized. 197 I am a speling mistakke. 198 ]] 199 200 setup_provider [[ 201 local ns = api.nvim_create_namespace "spell" 202 beamtrace = {} 203 local function on_do(kind, ...) 204 if kind == 'win' or kind == 'spell' then 205 api.nvim_buf_set_extmark(0, ns, 0, 0, { 206 end_row = 2, 207 end_col = 23, 208 spell = true, 209 priority = 20, 210 ephemeral = true 211 }) 212 end 213 table.insert(beamtrace, {kind, ...}) 214 end 215 ]] 216 217 check_trace { 218 { 'start', 5 }, 219 { 'win', 1000, 1, 0, 3 }, 220 { 'line', 1000, 1, 0 }, 221 { 'range', 1000, 1, 0, 0, 1, 0 }, 222 { 'line', 1000, 1, 1 }, 223 { 'range', 1000, 1, 1, 0, 2, 0 }, 224 { 'line', 1000, 1, 2 }, 225 { 'range', 1000, 1, 2, 0, 3, 0 }, 226 { 'line', 1000, 1, 3 }, 227 { 'range', 1000, 1, 3, 0, 4, 0 }, 228 { 'end', 5 }, 229 } 230 231 feed 'gg0' 232 233 screen:expect { 234 grid = [[ 235 ^I am well written text. | 236 {15:i} am not capitalized. | 237 I am a {16:speling} {16:mistakke}. | 238 | 239 {1:~ }|*3 240 | 241 ]], 242 } 243 244 feed ']s' 245 check_trace { 246 { 'spell', 1000, 1, 1, 0, 1, -1 }, 247 } 248 screen:expect { 249 grid = [[ 250 I am well written text. | 251 {15:^i} am not capitalized. | 252 I am a {16:speling} {16:mistakke}. | 253 | 254 {1:~ }|*3 255 | 256 ]], 257 } 258 259 feed ']s' 260 check_trace { 261 { 'spell', 1000, 1, 2, 7, 2, -1 }, 262 } 263 screen:expect { 264 grid = [[ 265 I am well written text. | 266 {15:i} am not capitalized. | 267 I am a {16:^speling} {16:mistakke}. | 268 | 269 {1:~ }|*3 270 | 271 ]], 272 } 273 274 -- spell=false with higher priority does disable spell 275 local ns = api.nvim_create_namespace 'spell' 276 local id = api.nvim_buf_set_extmark(0, ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false }) 277 278 screen:expect { 279 grid = [[ 280 I am well written text. | 281 i am not capitalized. | 282 I am a ^speling mistakke. | 283 | 284 {1:~ }|*3 285 | 286 ]], 287 } 288 289 feed ']s' 290 screen:expect { 291 grid = [[ 292 I am well written text. | 293 i am not capitalized. | 294 I am a ^speling mistakke. | 295 | 296 {1:~ }|*3 297 {17:search hit BOTTOM, continuing at TOP} | 298 ]], 299 } 300 command('echo ""') 301 302 -- spell=false with lower priority doesn't disable spell 303 api.nvim_buf_set_extmark(0, ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false }) 304 305 screen:expect { 306 grid = [[ 307 I am well written text. | 308 {15:i} am not capitalized. | 309 I am a {16:^speling} {16:mistakke}. | 310 | 311 {1:~ }|*3 312 | 313 ]], 314 } 315 316 feed ']s' 317 screen:expect { 318 grid = [[ 319 I am well written text. | 320 {15:i} am not capitalized. | 321 I am a {16:speling} {16:^mistakke}. | 322 | 323 {1:~ }|*3 324 | 325 ]], 326 } 327 end) 328 329 it('can predefine highlights', function() 330 screen:try_resize(40, 16) 331 insert(mulholland) 332 exec [[ 333 3 334 set ft=c 335 syntax on 336 set number cursorline 337 split 338 ]] 339 local ns1 = setup_provider() 340 341 for k, v in pairs { 342 LineNr = { italic = true, bg = 'Magenta' }, 343 Comment = { fg = '#FF0000', bg = 80 * 256 + 40 }, 344 CursorLine = { link = 'ErrorMsg' }, 345 } do 346 api.nvim_set_hl(ns1, k, v) 347 end 348 349 screen:expect { 350 grid = [[ 351 {3: 1 }{4:// just to see if there was an accid}| 352 {3: }{4:ent} | 353 {3: 2 }{4:// on Mulholland Drive} | 354 {6: 3 }{7:^try_start(); }| 355 {3: 4 }bufref_T save_buf; | 356 {3: 5 }switch_buffer(&save_buf, buf); | 357 {3: 6 }posp = getmark(mark, {5:false}); | 358 {8:[No Name] [+] }| 359 {3: 2 }{4:// on Mulholland Drive} | 360 {6: 3 }{7:try_start(); }| 361 {3: 4 }bufref_T save_buf; | 362 {3: 5 }switch_buffer(&save_buf, buf); | 363 {3: 6 }posp = getmark(mark, {5:false}); | 364 {3: 7 }restore_buffer(&save_buf); | 365 {9:[No Name] [+] }| 366 | 367 ]], 368 } 369 370 api.nvim_set_hl_ns(ns1) 371 screen:expect { 372 grid = [[ 373 {10: 1 }{11:// just to see if there was an accid}| 374 {10: }{11:ent} | 375 {10: 2 }{11:// on Mulholland Drive} | 376 {6: 3 }{2:^try_start(); }| 377 {10: 4 }bufref_T save_buf; | 378 {10: 5 }switch_buffer(&save_buf, buf); | 379 {10: 6 }posp = getmark(mark, {5:false}); | 380 {8:[No Name] [+] }| 381 {10: 2 }{11:// on Mulholland Drive} | 382 {6: 3 }{2:try_start(); }| 383 {10: 4 }bufref_T save_buf; | 384 {10: 5 }switch_buffer(&save_buf, buf); | 385 {10: 6 }posp = getmark(mark, {5:false}); | 386 {10: 7 }restore_buffer(&save_buf); | 387 {9:[No Name] [+] }| 388 | 389 ]], 390 } 391 392 exec_lua [[ 393 local api = vim.api 394 local thewin = api.nvim_get_current_win() 395 local ns2 = api.nvim_create_namespace 'ns2' 396 api.nvim_set_decoration_provider (ns2, { 397 on_win = function (_, win, buf) 398 api.nvim_set_hl_ns_fast(win == thewin and _G.ns1 or ns2) 399 end; 400 }) 401 ]] 402 screen:expect { 403 grid = [[ 404 {10: 1 }{11:// just to see if there was an accid}| 405 {10: }{11:ent} | 406 {10: 2 }{11:// on Mulholland Drive} | 407 {6: 3 }{2:^try_start(); }| 408 {10: 4 }bufref_T save_buf; | 409 {10: 5 }switch_buffer(&save_buf, buf); | 410 {10: 6 }posp = getmark(mark, {5:false}); | 411 {8:[No Name] [+] }| 412 {3: 2 }{4:// on Mulholland Drive} | 413 {6: 3 }{7:try_start(); }| 414 {3: 4 }bufref_T save_buf; | 415 {3: 5 }switch_buffer(&save_buf, buf); | 416 {3: 6 }posp = getmark(mark, {5:false}); | 417 {3: 7 }restore_buffer(&save_buf); | 418 {9:[No Name] [+] }| 419 | 420 ]], 421 } 422 end) 423 424 it('can break an existing link', function() 425 insert(mulholland) 426 local ns1 = setup_provider() 427 428 exec [[ 429 highlight OriginalGroup guifg='#990000' 430 highlight link LinkGroup OriginalGroup 431 ]] 432 433 api.nvim_buf_set_virtual_text(0, 0, 2, { { '- not red', 'LinkGroup' } }, {}) 434 screen:expect { 435 grid = [[ 436 // just to see if there was an accident | 437 // on Mulholland Drive | 438 try_start(); {12:- not red} | 439 bufref_T save_buf; | 440 switch_buffer(&save_buf, buf); | 441 posp = getmark(mark, false); | 442 restore_buffer(&save_buf);^ | 443 | 444 ]], 445 } 446 447 api.nvim_set_hl(ns1, 'LinkGroup', { fg = 'Blue' }) 448 api.nvim_set_hl_ns(ns1) 449 450 screen:expect { 451 grid = [[ 452 // just to see if there was an accident | 453 // on Mulholland Drive | 454 try_start(); {4:- not red} | 455 bufref_T save_buf; | 456 switch_buffer(&save_buf, buf); | 457 posp = getmark(mark, false); | 458 restore_buffer(&save_buf);^ | 459 | 460 ]], 461 } 462 end) 463 464 it("with 'default': do not break an existing link", function() 465 insert(mulholland) 466 local ns1 = setup_provider() 467 468 exec [[ 469 highlight OriginalGroup guifg='#990000' 470 highlight link LinkGroup OriginalGroup 471 ]] 472 473 api.nvim_buf_set_virtual_text(0, 0, 2, { { '- not red', 'LinkGroup' } }, {}) 474 screen:expect { 475 grid = [[ 476 // just to see if there was an accident | 477 // on Mulholland Drive | 478 try_start(); {12:- not red} | 479 bufref_T save_buf; | 480 switch_buffer(&save_buf, buf); | 481 posp = getmark(mark, false); | 482 restore_buffer(&save_buf);^ | 483 | 484 ]], 485 } 486 487 api.nvim_set_hl(ns1, 'LinkGroup', { fg = 'Blue', default = true }) 488 api.nvim_set_hl_ns(ns1) 489 feed 'k' 490 491 screen:expect { 492 grid = [[ 493 // just to see if there was an accident | 494 // on Mulholland Drive | 495 try_start(); {12:- not red} | 496 bufref_T save_buf; | 497 switch_buffer(&save_buf, buf); | 498 posp = getmark(mark, false^); | 499 restore_buffer(&save_buf); | 500 | 501 ]], 502 } 503 end) 504 505 it('can have virtual text', function() 506 insert(mulholland) 507 setup_provider [[ 508 local hl = api.nvim_get_hl_id_by_name "ErrorMsg" 509 local test_ns = api.nvim_create_namespace "mulholland" 510 function on_do(event, ...) 511 if event == "line" then 512 local win, buf, line = ... 513 api.nvim_buf_set_extmark(buf, test_ns, line, 0, { 514 virt_text = {{'+', 'ErrorMsg'}}; 515 virt_text_pos='overlay'; 516 ephemeral = true; 517 }) 518 end 519 end 520 ]] 521 522 screen:expect { 523 grid = [[ 524 {2:+}/ just to see if there was an accident | 525 {2:+}/ on Mulholland Drive | 526 {2:+}ry_start(); | 527 {2:+}ufref_T save_buf; | 528 {2:+}witch_buffer(&save_buf, buf); | 529 {2:+}osp = getmark(mark, false); | 530 {2:+}estore_buffer(&save_buf);^ | 531 | 532 ]], 533 } 534 end) 535 536 it('can have virtual text of the style: right_align', function() 537 insert(mulholland) 538 setup_provider [[ 539 local hl = api.nvim_get_hl_id_by_name "ErrorMsg" 540 local test_ns = api.nvim_create_namespace "mulholland" 541 function on_do(event, ...) 542 if event == "line" then 543 local win, buf, line = ... 544 api.nvim_buf_set_extmark(buf, test_ns, line, 0, { 545 virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}}; 546 virt_text_pos='right_align'; 547 ephemeral = true; 548 }) 549 end 550 end 551 ]] 552 553 screen:expect { 554 grid = [[ 555 // just to see if there was an acciden+{2: }| 556 // on Mulholland Drive +{2: }| 557 try_start(); +{2: }| 558 bufref_T save_buf; +{2: }| 559 switch_buffer(&save_buf, buf); +{2: }| 560 posp = getmark(mark, false); +{2: }| 561 restore_buffer(&save_buf);^ +{2: }| 562 | 563 ]], 564 } 565 end) 566 567 it('can have virtual text of the style: eol_right_align', function() 568 insert(mulholland) 569 setup_provider [[ 570 local hl = api.nvim_get_hl_id_by_name "ErrorMsg" 571 local test_ns = api.nvim_create_namespace "mulholland" 572 function on_do(event, ...) 573 if event == "line" then 574 local win, buf, line = ... 575 api.nvim_buf_set_extmark(buf, test_ns, line, 0, { 576 virt_text = {{'+'}, {'1234567890', 'ErrorMsg'}}; 577 virt_text_pos='eol_right_align'; 578 ephemeral = true; 579 }) 580 end 581 end 582 ]] 583 584 screen:expect { 585 grid = [[ 586 // just to see if there was an accident | 587 // on Mulholland Drive +{2:1234567890}| 588 try_start(); +{2:1234567890}| 589 bufref_T save_buf; +{2:1234567890}| 590 switch_buffer(&save_buf, buf); +{2:12345678}| 591 posp = getmark(mark, false); +{2:1234567890}| 592 restore_buffer(&save_buf);^ +{2:1234567890}| 593 | 594 ]], 595 } 596 end) 597 598 it('multiple eol_right_align', function() 599 insert(mulholland) 600 setup_provider [[ 601 local hl = api.nvim_get_hl_id_by_name "ErrorMsg" 602 local test_ns = api.nvim_create_namespace "mulholland" 603 function on_do(event, ...) 604 if event == "line" then 605 local win, buf, line = ... 606 api.nvim_buf_set_extmark(buf, test_ns, line, 0, { 607 virt_text = {{'11111'}}; 608 virt_text_pos='eol_right_align'; 609 ephemeral = true; 610 }) 611 api.nvim_buf_set_extmark(0, test_ns, line, 0, { 612 virt_text = {{'22222'}}; 613 virt_text_pos='eol_right_align'; 614 ephemeral = true; 615 }) 616 end 617 end 618 ]] 619 620 screen:expect { 621 grid = [[ 622 // just to see if there was an accident | 623 // on Mulholland Drive 11111 22222| 624 try_start(); 11111 22222| 625 bufref_T save_buf; 11111 22222| 626 switch_buffer(&save_buf, buf); 11111 222| 627 posp = getmark(mark, false); 11111 22222| 628 restore_buffer(&save_buf);^ 11111 22222| 629 | 630 ]], 631 } 632 end) 633 634 it('eol_right_align: second text much longer than first', function() 635 insert('short') 636 setup_provider [[ 637 local test_ns = api.nvim_create_namespace "test_length_diff" 638 function on_do(event, ...) 639 if event == "line" then 640 local win, buf, line = ... 641 642 api.nvim_buf_set_extmark(buf, test_ns, line, 0, { 643 virt_text = {{'AA', 'Comment'}}; 644 virt_text_pos = 'eol_right_align'; 645 priority = 100; 646 ephemeral = true; 647 }) 648 649 api.nvim_buf_set_extmark(buf, test_ns, line, 0, { 650 virt_text = {{'BBBBBBBBBBBBBBBBBBBB', 'ErrorMsg'}}; 651 virt_text_pos = 'eol_right_align'; 652 priority = 200; 653 ephemeral = true; 654 }) 655 end 656 end 657 ]] 658 659 screen:expect([[ 660 shor^t {4:AA} {2:BBBBBBBBBBBBBBBBBBBB}| 661 {1:~ }|*6 662 | 663 ]]) 664 end) 665 666 it('virtual text works with wrapped lines', function() 667 insert(mulholland) 668 feed('ggJj3JjJ') 669 setup_provider [[ 670 local hl = api.nvim_get_hl_id_by_name "ErrorMsg" 671 local test_ns = api.nvim_create_namespace "mulholland" 672 function on_do(event, ...) 673 if event == "line" then 674 local win, buf, line = ... 675 api.nvim_buf_set_extmark(buf, test_ns, line, 0, { 676 virt_text = {{string.rep('/', line+1), 'ErrorMsg'}}; 677 virt_text_pos='eol'; 678 ephemeral = true; 679 }) 680 api.nvim_buf_set_extmark(buf, test_ns, line, 6, { 681 virt_text = {{string.rep('*', line+1), 'ErrorMsg'}}; 682 virt_text_pos='overlay'; 683 ephemeral = true; 684 }) 685 api.nvim_buf_set_extmark(buf, test_ns, line, 39, { 686 virt_text = {{string.rep('!', line+1), 'ErrorMsg'}}; 687 virt_text_win_col=20; 688 ephemeral = true; 689 }) 690 api.nvim_buf_set_extmark(buf, test_ns, line, 40, { 691 virt_text = {{string.rep('?', line+1), 'ErrorMsg'}}; 692 virt_text_win_col=10; 693 ephemeral = true; 694 }) 695 api.nvim_buf_set_extmark(buf, test_ns, line, 40, { 696 virt_text = {{string.rep(';', line+1), 'ErrorMsg'}}; 697 virt_text_pos='overlay'; 698 ephemeral = true; 699 }) 700 api.nvim_buf_set_extmark(buf, test_ns, line, 40, { 701 virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}}; 702 virt_text_pos='right_align'; 703 ephemeral = true; 704 }) 705 end 706 end 707 ]] 708 709 screen:expect { 710 grid = [[ 711 // jus{2:*} to see if th{2:!}re was an accident | 712 {2:;}n Mulholl{2:?}nd Drive {2:/} +{2: }| 713 try_st{2:**}t(); bufref_{2:!!}save_buf; switch_b| 714 {2:;;}fer(&sav{2:??}buf, buf); {2://} +{2: }| 715 posp ={2:***}tmark(mark,{2:!!!}lse);^ restore_buf| 716 {2:;;;}(&save_{2:???}); {2:///} +{2: }| 717 {1:~ }| 718 | 719 ]], 720 } 721 command('setlocal breakindent breakindentopt=shift:2') 722 screen:expect { 723 grid = [[ 724 // jus{2:*} to see if th{2:!}re was an accident | 725 {2:;}n Mulho{2:?}land Drive {2:/} +{2: }| 726 try_st{2:**}t(); bufref_{2:!!}save_buf; switch_b| 727 {2:;;}fer(&s{2:??}e_buf, buf); {2://} +{2: }| 728 posp ={2:***}tmark(mark,{2:!!!}lse);^ restore_buf| 729 {2:;;;}(&sav{2:???}uf); {2:///} +{2: }| 730 {1:~ }| 731 | 732 ]], 733 } 734 end) 735 736 it('can highlight beyond EOL', function() 737 insert(mulholland) 738 setup_provider [[ 739 local test_ns = api.nvim_create_namespace "veberod" 740 function on_do(event, ...) 741 if event == "line" then 742 local win, buf, line = ... 743 if string.find(api.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then 744 api.nvim_buf_set_extmark(buf, test_ns, line, 0, { 745 end_line = line+1; 746 hl_group = 'DiffAdd'; 747 hl_eol = true; 748 ephemeral = true; 749 }) 750 end 751 end 752 end 753 ]] 754 755 screen:expect { 756 grid = [[ 757 // just to see if there was an accident | 758 // on Mulholland Drive | 759 try_start(); | 760 {13:bufref_T save_buf; }| 761 {13:switch_buffer(&save_buf, buf); }| 762 posp = getmark(mark, false); | 763 {13:restore_buffer(&save_buf);^ }| 764 | 765 ]], 766 } 767 end) 768 769 it('can create and remove signs when CursorMoved autocommand validates botline #18661', function() 770 exec_lua([[ 771 local lines = {} 772 for i = 1, 200 do 773 lines[i] = 'hello' .. tostring(i) 774 end 775 vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) 776 ]]) 777 setup_provider([[ 778 local function on_do(kind, winid, bufnr, topline, botline) 779 if kind == 'win' then 780 if topline < 100 and botline > 100 then 781 api.nvim_buf_set_extmark(bufnr, ns1, 99, -1, { sign_text = 'X' }) 782 else 783 api.nvim_buf_clear_namespace(bufnr, ns1, 0, -1) 784 end 785 end 786 end 787 ]]) 788 command([[autocmd CursorMoved * call line('w$')]]) 789 api.nvim_win_set_cursor(0, { 100, 0 }) 790 screen:expect([[ 791 {14: }hello97 | 792 {14: }hello98 | 793 {14: }hello99 | 794 {14:X }^hello100 | 795 {14: }hello101 | 796 {14: }hello102 | 797 {14: }hello103 | 798 | 799 ]]) 800 api.nvim_win_set_cursor(0, { 1, 0 }) 801 screen:expect([[ 802 ^hello1 | 803 hello2 | 804 hello3 | 805 hello4 | 806 hello5 | 807 hello6 | 808 hello7 | 809 | 810 ]]) 811 end) 812 813 it('does allow removing extmarks during on_line callbacks', function() 814 exec_lua([[ 815 eok = true 816 ]]) 817 setup_provider([[ 818 local function on_do(kind, winid, bufnr, topline, botline) 819 if kind == 'line' then 820 api.nvim_buf_set_extmark(bufnr, ns1, 1, -1, { sign_text = 'X' }) 821 eok = pcall(api.nvim_buf_clear_namespace, bufnr, ns1, 0, -1) 822 end 823 end 824 ]]) 825 exec_lua([[ 826 assert(eok == true) 827 ]]) 828 end) 829 830 it('on_line is invoked only for buffer lines', function() 831 insert(mulholland) 832 command('vnew') 833 insert(mulholland) 834 feed('dd') 835 command('windo diffthis') 836 837 exec_lua([[ 838 out_of_bound = false 839 ]]) 840 setup_provider([[ 841 local function on_do(kind, _, bufnr, row) 842 if kind == 'line' then 843 if not api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] then 844 out_of_bound = true 845 end 846 end 847 end 848 ]]) 849 850 feed('<C-e>') 851 852 exec_lua([[ 853 assert(out_of_bound == false) 854 ]]) 855 end) 856 857 it('on_range is invoked on all visible characters', function() 858 clear() 859 screen = Screen.new(20, 4) 860 setup_screen(screen) 861 862 local function record() 863 exec_lua(function() 864 _G.p_min = { math.huge, math.huge } 865 _G.p_max = { -math.huge, -math.huge } 866 function _G.pos_gt(a, b) 867 return a[1] > b[1] or (a[1] == b[1] and a[2] > b[2]) 868 end 869 function _G.pos_lt(a, b) 870 return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2]) 871 end 872 end) 873 setup_provider [[ 874 local function on_do(kind, _, bufnr, br, bc, er, ec) 875 if kind == 'range' then 876 local b = { br, bc } 877 local e = { er, ec } 878 if _G.pos_gt(_G.p_min, b) then 879 _G.p_min = b 880 end 881 if _G.pos_lt(_G.p_max, e) then 882 _G.p_max = e 883 end 884 end 885 end 886 ]] 887 end 888 local function check(min, max) 889 local p_min = exec_lua('return _G.p_min') 890 assert( 891 p_min[1] < min[1] or (p_min[1] == min[1] and p_min[2] <= min[2]), 892 'minimum position ' .. vim.inspect(p_min) .. ' should be before the first char' 893 ) 894 local p_max = exec_lua('return _G.p_max') 895 assert( 896 p_max[1] > max[1] or (p_max[1] == max[1] and p_max[2] >= max[2]), 897 'maximum position ' .. vim.inspect(p_max) .. ' should be on or after the last char' 898 ) 899 end 900 901 -- Multiple lines. 902 exec_lua([[ 903 local lines = { ('a'):rep(40), ('b'):rep(40), ('c'):rep(40) } 904 vim.api.nvim_buf_set_lines(0, 0, -1, true, lines) 905 vim.api.nvim_win_set_cursor(0, { 2, 0 }) 906 ]]) 907 record() 908 screen:expect([[ 909 ^bbbbbbbbbbbbbbbbbbbb| 910 bbbbbbbbbbbbbbbbbbbb| 911 ccccccccccccccccc{1:@@@}| 912 | 913 ]]) 914 check({ 1, 0 }, { 2, 21 }) 915 916 -- One long line. 917 exec_lua([[ 918 local lines = { ('a'):rep(100) } 919 vim.api.nvim_buf_set_lines(0, 0, -1, true, lines) 920 vim.api.nvim_win_set_cursor(0, { 1, 70 }) 921 ]]) 922 record() 923 screen:expect([[ 924 {1:<<<}aaaaaaaaaaaaaaaaa| 925 aaaaaaaaaaaaaaaaaaaa| 926 aaaaaaaaaa^aaaaaaaaaa| 927 | 928 ]]) 929 check({ 0, 20 }, { 0, 81 }) 930 931 -- Multibyte characters. 932 exec_lua([[ 933 local lines = { ('\195\162'):rep(100) } 934 vim.api.nvim_buf_set_lines(0, 0, -1, true, lines) 935 vim.api.nvim_win_set_cursor(0, { 1, 70 * 2 }) 936 ]]) 937 record() 938 screen:expect([[ 939 {1:<<<}âââââââââââââââââ| 940 ââââââââââââââââââââ| 941 ââââââââââ^ââââââââââ| 942 | 943 ]]) 944 check({ 0, 20 * 2 }, { 0, 81 * 2 }) 945 946 -- Tabs. 947 exec_lua([[ 948 local lines = { 'a' .. ('\t'):rep(100) } 949 vim.api.nvim_buf_set_lines(0, 0, -1, true, lines) 950 vim.api.nvim_win_set_cursor(0, { 1, 39 }) 951 ]]) 952 record() 953 screen:expect([[ 954 {1:<<<} | 955 | 956 ^ | 957 | 958 ]]) 959 check({ 0, 33 }, { 0, 94 }) 960 961 -- One long line without wrapping. 962 command('set nowrap') 963 exec_lua([[ 964 local lines = { ('a'):rep(50) .. ('b'):rep(50) } 965 vim.api.nvim_buf_set_lines(0, 0, -1, true, lines) 966 vim.api.nvim_win_set_cursor(0, { 1, 50 }) 967 ]]) 968 record() 969 screen:expect([[ 970 aaaaaaaaaa^bbbbbbbbbb| 971 {1:~ }|*2 972 | 973 ]]) 974 check({ 0, 40 }, { 0, 60 }) 975 end) 976 977 it('can add new providers during redraw #26652', function() 978 setup_provider [[ 979 local ns = api.nvim_create_namespace('test_no_add') 980 function on_do(...) 981 api.nvim_set_decoration_provider(ns, {}) 982 end 983 ]] 984 985 n.assert_alive() 986 end) 987 988 it('is not invoked repeatedly in Visual mode with vim.schedule() #20235', function() 989 exec_lua([[_G.cnt = 0]]) 990 setup_provider([[ 991 function on_do(event, ...) 992 if event == 'win' then 993 vim.schedule(function() end) 994 _G.cnt = _G.cnt + 1 995 end 996 end 997 ]]) 998 feed('v') 999 screen:expect([[ 1000 ^ | 1001 {1:~ }|*6 1002 {19:-- VISUAL --} | 1003 ]]) 1004 eq(2, exec_lua([[return _G.cnt]])) 1005 end) 1006 1007 it('can do large changes to the marktree', function() 1008 insert('line1 with a lot of text\nline2 with a lot of text') 1009 setup_provider([[ 1010 function on_do(event, _, _, row) 1011 if event == 'win' or (event == 'line' and row == 1) then 1012 vim.api.nvim_buf_clear_namespace(0, ns1, 0, -1) 1013 for i = 0,1 do 1014 for j = 0,23 do 1015 vim.api.nvim_buf_set_extmark(0, ns1, i, j, {hl_group='ErrorMsg', end_col = j+1}) 1016 end 1017 end 1018 end 1019 end 1020 ]]) 1021 1022 -- Doesn't crash when modifying the marktree between line1 and line2 1023 screen:expect([[ 1024 {2:line1 with a lot of text} | 1025 {2:line2 with a lot of tex^t} | 1026 {1:~ }|*5 1027 | 1028 ]]) 1029 end) 1030 1031 it('inline virt_text does not result in wrong cursor column #33153', function() 1032 insert('line1 with a lot of text\nline2 with a lot of text') 1033 setup_provider([[ 1034 _G.do_win = false 1035 vim.keymap.set('n', 'f', function() 1036 _G.do_win = true 1037 vim.cmd('redraw!') 1038 end) 1039 vim.o.concealcursor = 'n' 1040 function on_do(event) 1041 if event == 'win' and _G.do_win then 1042 vim.api.nvim_buf_set_extmark(0, ns1, 1, 0, { 1043 virt_text = { { 'virt_text ' } }, 1044 virt_text_pos = 'inline' 1045 }) 1046 end 1047 end 1048 ]]) 1049 feed('f') 1050 screen:expect([[ 1051 line1 with a lot of text | 1052 virt_text line2 with a lot of tex^t | 1053 {1:~ }|*5 1054 | 1055 ]]) 1056 end) 1057 1058 it('decor provider is enabled again for next redraw after on_win disabled it', function() 1059 exec_lua(function() 1060 vim.api.nvim_set_decoration_provider(vim.api.nvim_create_namespace(''), { 1061 on_win = function() 1062 return false 1063 end, 1064 on_buf = function() 1065 _G.did_buf = (_G.did_buf or 0) + 1 1066 end, 1067 }) 1068 end) 1069 api.nvim_buf_set_lines(0, 0, -1, false, { 'foo' }) 1070 screen:expect([[ 1071 ^foo | 1072 {1:~ }|*6 1073 | 1074 ]]) 1075 eq(1, exec_lua('return _G.did_buf')) 1076 end) 1077 end) 1078 1079 describe('decoration_providers', function() 1080 it('errors and logs gracefully', function() 1081 local testlog = 'Xtest_decorations_log' 1082 clear({ env = { NVIM_LOG_FILE = testlog } }) 1083 local screen = Screen.new(65, 7) 1084 setup_provider([[ 1085 function on_do(...) 1086 error "Foo" 1087 end 1088 ]]) 1089 screen:expect([[ 1090 {3: }| 1091 {9:Decoration provider "start" (ns=ns1):} | 1092 {9:Lua: [string "<nvim>"]:4: Foo} | 1093 {9:stack traceback:} | 1094 {9: [C]: in function 'error'} | 1095 {9: [string "<nvim>"]:4: in function <[string "<nvim>"]:3>} | 1096 {6:Press ENTER or type command to continue}^ | 1097 ]]) 1098 t.assert_log('Error in decoration provider "start" %(ns=ns1%):', testlog, 100) 1099 t.assert_log('Lua: %[string "<nvim>"%]:4: Foo', testlog, 100) 1100 n.check_close() 1101 os.remove(testlog) 1102 end) 1103 end) 1104 1105 local example_text = [[ 1106 for _,item in ipairs(items) do 1107 local text, hl_id_cell, count = unpack(item) 1108 if hl_id_cell ~= nil then 1109 hl_id = hl_id_cell 1110 end 1111 for _ = 1, (count or 1) do 1112 local cell = line[colpos] 1113 cell.text = text 1114 cell.hl_id = hl_id 1115 colpos = colpos+1 1116 end 1117 end]] 1118 1119 describe('extmark decorations', function() 1120 local screen ---@type test.functional.ui.screen 1121 local ns ---@type integer 1122 before_each(function() 1123 clear() 1124 screen = Screen.new(50, 15) 1125 screen:set_default_attr_ids { 1126 [1] = { bold = true, foreground = Screen.colors.Blue }, 1127 [2] = { foreground = Screen.colors.Brown }, 1128 [3] = { bold = true, foreground = Screen.colors.SeaGreen }, 1129 [4] = { background = Screen.colors.Red1, foreground = Screen.colors.Gray100 }, 1130 [5] = { foreground = Screen.colors.Brown, bold = true }, 1131 [6] = { foreground = Screen.colors.DarkCyan }, 1132 [7] = { foreground = Screen.colors.Grey0, background = tonumber('0xff4c4c') }, 1133 [8] = { foreground = tonumber('0x180606'), background = tonumber('0xff4c4c') }, 1134 [9] = { foreground = tonumber('0xe40c0c'), background = tonumber('0xff4c4c'), bold = true }, 1135 [10] = { foreground = tonumber('0xb20000'), background = tonumber('0xff4c4c') }, 1136 [11] = { blend = 30, background = Screen.colors.Red1 }, 1137 [12] = { foreground = Screen.colors.Brown, blend = 30, background = Screen.colors.Red1, bold = true }, 1138 [13] = { foreground = Screen.colors.Fuchsia }, 1139 [14] = { background = Screen.colors.Red1, foreground = Screen.colors.Black }, 1140 [15] = { background = Screen.colors.Red1, foreground = tonumber('0xb20000') }, 1141 [16] = { blend = 30, background = Screen.colors.Red1, foreground = Screen.colors.Magenta1 }, 1142 [17] = { bold = true, foreground = Screen.colors.Brown, background = Screen.colors.LightGrey }, 1143 [18] = { background = Screen.colors.LightGrey }, 1144 [19] = { foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGrey }, 1145 [20] = { foreground = tonumber('0x180606'), background = tonumber('0xf13f3f') }, 1146 [21] = { foreground = Screen.colors.Gray0, background = tonumber('0xf13f3f') }, 1147 [22] = { foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f') }, 1148 [23] = { foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey }, 1149 [24] = { bold = true }, 1150 [25] = { background = Screen.colors.LightRed }, 1151 [26] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey }, 1152 [27] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black }, 1153 [28] = { underline = true, foreground = Screen.colors.SlateBlue }, 1154 [29] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.LightGrey, underline = true }, 1155 [30] = { foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGrey, underline = true }, 1156 [31] = { underline = true, foreground = Screen.colors.DarkCyan }, 1157 [32] = { underline = true }, 1158 [33] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey }, 1159 [34] = { background = Screen.colors.Yellow }, 1160 [35] = { background = Screen.colors.Yellow, bold = true, foreground = Screen.colors.Blue }, 1161 [36] = { foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.Red }, 1162 [37] = { background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue }, 1163 [38] = { background = Screen.colors.LightBlue }, 1164 [39] = { foreground = Screen.colors.Blue1, background = Screen.colors.LightCyan1, bold = true }, 1165 [40] = { reverse = true }, 1166 [41] = { bold = true, reverse = true }, 1167 [42] = { undercurl = true, special = Screen.colors.Red }, 1168 [43] = { background = Screen.colors.Yellow, undercurl = true, special = Screen.colors.Red }, 1169 [44] = { background = Screen.colors.LightMagenta }, 1170 [45] = { background = Screen.colors.Red, special = Screen.colors.Red, foreground = Screen.colors.Red }, 1171 [46] = { background = Screen.colors.Blue, foreground = Screen.colors.Blue, special = Screen.colors.Red }, 1172 [47] = { background = Screen.colors.Green, foreground = Screen.colors.Blue, special = Screen.colors.Red }, 1173 } 1174 1175 ns = api.nvim_create_namespace 'test' 1176 end) 1177 1178 it('empty virtual text at eol should not break colorcolumn #17860', function() 1179 insert(example_text) 1180 feed('gg') 1181 command('set colorcolumn=40') 1182 screen:expect([[ 1183 ^for _,item in ipairs(items) do {25: } | 1184 local text, hl_id_cell, count = unp{25:a}ck(item) | 1185 if hl_id_cell ~= nil then {25: } | 1186 hl_id = hl_id_cell {25: } | 1187 end {25: } | 1188 for _ = 1, (count or 1) do {25: } | 1189 local cell = line[colpos] {25: } | 1190 cell.text = text {25: } | 1191 cell.hl_id = hl_id {25: } | 1192 colpos = colpos+1 {25: } | 1193 end {25: } | 1194 end {25: } | 1195 {1:~ }|*2 1196 | 1197 ]]) 1198 api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_text = { { '' } }, virt_text_pos = 'eol' }) 1199 screen:expect_unchanged() 1200 end) 1201 1202 it('can have virtual text of overlay position', function() 1203 insert(example_text) 1204 feed 'gg' 1205 1206 for i = 1, 9 do 1207 api.nvim_buf_set_extmark(0, ns, i, 0, { virt_text = { { '|', 'LineNr' } }, virt_text_pos = 'overlay' }) 1208 if i == 3 or (i >= 6 and i <= 9) then 1209 api.nvim_buf_set_extmark(0, ns, i, 4, { virt_text = { { '|', 'NonText' } }, virt_text_pos = 'overlay' }) 1210 end 1211 end 1212 api.nvim_buf_set_extmark( 1213 0, 1214 ns, 1215 9, 1216 10, 1217 { virt_text = { { 'foo' }, { 'bar', 'MoreMsg' }, { '!!', 'ErrorMsg' } }, virt_text_pos = 'overlay' } 1218 ) 1219 1220 -- can "float" beyond end of line 1221 api.nvim_buf_set_extmark(0, ns, 5, 28, { virt_text = { { 'loopy', 'ErrorMsg' } }, virt_text_pos = 'overlay' }) 1222 -- bound check: right edge of window 1223 api.nvim_buf_set_extmark( 1224 0, 1225 ns, 1226 2, 1227 26, 1228 { virt_text = { { 'bork bork bork' }, { (' bork'):rep(10), 'ErrorMsg' } }, virt_text_pos = 'overlay' } 1229 ) 1230 -- empty virt_text should not change anything 1231 api.nvim_buf_set_extmark(0, ns, 6, 16, { virt_text = { { '' } }, virt_text_pos = 'overlay' }) 1232 1233 screen:expect { 1234 grid = [[ 1235 ^for _,item in ipairs(items) do | 1236 {2:|} local text, hl_id_cell, count = unpack(item) | 1237 {2:|} if hl_id_cell ~= nil tbork bork bork{4: bork bork}| 1238 {2:|} {1:|} hl_id = hl_id_cell | 1239 {2:|} end | 1240 {2:|} for _ = 1, (count or 1) {4:loopy} | 1241 {2:|} {1:|} local cell = line[colpos] | 1242 {2:|} {1:|} cell.text = text | 1243 {2:|} {1:|} cell.hl_id = hl_id | 1244 {2:|} {1:|} cofoo{3:bar}{4:!!}olpos+1 | 1245 end | 1246 end | 1247 {1:~ }|*2 1248 | 1249 ]], 1250 } 1251 1252 -- handles broken lines 1253 screen:try_resize(22, 25) 1254 screen:expect { 1255 grid = [[ 1256 ^for _,item in ipairs(i| 1257 tems) do | 1258 {2:|} local text, hl_id_| 1259 cell, count = unpack(i| 1260 tem) | 1261 {2:|} if hl_id_cell ~= n| 1262 il tbork bork bork{4: bor}| 1263 {2:|} {1:|} hl_id = hl_id_| 1264 cell | 1265 {2:|} end | 1266 {2:|} for _ = 1, (count | 1267 or 1) {4:loopy} | 1268 {2:|} {1:|} local cell = l| 1269 ine[colpos] | 1270 {2:|} {1:|} cell.text = te| 1271 xt | 1272 {2:|} {1:|} cell.hl_id = h| 1273 l_id | 1274 {2:|} {1:|} cofoo{3:bar}{4:!!}olpo| 1275 s+1 | 1276 end | 1277 end | 1278 {1:~ }|*2 1279 | 1280 ]], 1281 } 1282 1283 -- truncating in the middle of a char leaves a space 1284 api.nvim_buf_set_lines(0, 0, 1, true, { 'for _,item in ipairs(items) do -- 古古古' }) 1285 api.nvim_buf_set_lines(0, 10, 12, true, { ' end -- ??????????', 'end -- ?古古古古?古古' }) 1286 api.nvim_buf_set_extmark(0, ns, 0, 35, { virt_text = { { 'A', 'ErrorMsg' }, { 'AA' } }, virt_text_pos = 'overlay' }) 1287 api.nvim_buf_set_extmark(0, ns, 10, 19, { virt_text = { { '口口口', 'ErrorMsg' } }, virt_text_pos = 'overlay' }) 1288 api.nvim_buf_set_extmark(0, ns, 11, 21, { virt_text = { { '口口口', 'ErrorMsg' } }, virt_text_pos = 'overlay' }) 1289 api.nvim_buf_set_extmark(0, ns, 11, 8, { virt_text = { { '口口', 'ErrorMsg' } }, virt_text_pos = 'overlay' }) 1290 screen:expect { 1291 grid = [[ 1292 ^for _,item in ipairs(i| 1293 tems) do -- {4:A}AA 古 | 1294 {2:|} local text, hl_id_| 1295 cell, count = unpack(i| 1296 tem) | 1297 {2:|} if hl_id_cell ~= n| 1298 il tbork bork bork{4: bor}| 1299 {2:|} {1:|} hl_id = hl_id_| 1300 cell | 1301 {2:|} end | 1302 {2:|} for _ = 1, (count | 1303 or 1) {4:loopy} | 1304 {2:|} {1:|} local cell = l| 1305 ine[colpos] | 1306 {2:|} {1:|} cell.text = te| 1307 xt | 1308 {2:|} {1:|} cell.hl_id = h| 1309 l_id | 1310 {2:|} {1:|} cofoo{3:bar}{4:!!}olpo| 1311 s+1 | 1312 end -- ???????{4:口 }| 1313 end -- {4:口口} 古古{4:口口 }| 1314 {1:~ }|*2 1315 | 1316 ]], 1317 } 1318 1319 screen:try_resize(82, 13) 1320 screen:expect { 1321 grid = [[ 1322 ^for _,item in ipairs(items) do -- {4:A}AA 古 | 1323 {2:|} local text, hl_id_cell, count = unpack(item) | 1324 {2:|} if hl_id_cell ~= nil tbork bork bork{4: bork bork bork bork bork bork bork bork b}| 1325 {2:|} {1:|} hl_id = hl_id_cell | 1326 {2:|} end | 1327 {2:|} for _ = 1, (count or 1) {4:loopy} | 1328 {2:|} {1:|} local cell = line[colpos] | 1329 {2:|} {1:|} cell.text = text | 1330 {2:|} {1:|} cell.hl_id = hl_id | 1331 {2:|} {1:|} cofoo{3:bar}{4:!!}olpos+1 | 1332 end -- ???????{4:口口口} | 1333 end -- {4:口口} 古古{4:口口口} | 1334 | 1335 ]], 1336 } 1337 1338 api.nvim_buf_clear_namespace(0, ns, 0, -1) 1339 screen:expect { 1340 grid = [[ 1341 ^for _,item in ipairs(items) do -- 古古古 | 1342 local text, hl_id_cell, count = unpack(item) | 1343 if hl_id_cell ~= nil then | 1344 hl_id = hl_id_cell | 1345 end | 1346 for _ = 1, (count or 1) do | 1347 local cell = line[colpos] | 1348 cell.text = text | 1349 cell.hl_id = hl_id | 1350 colpos = colpos+1 | 1351 end -- ?????????? | 1352 end -- ?古古古古?古古 | 1353 | 1354 ]], 1355 } 1356 end) 1357 1358 it('overlay virtual text works with wrapped lines #25158', function() 1359 screen:try_resize(50, 6) 1360 insert(('ab'):rep(100)) 1361 for i = 0, 9 do 1362 api.nvim_buf_set_extmark(0, ns, 0, 42 + i, { virt_text = { { tostring(i), 'ErrorMsg' } }, virt_text_pos = 'overlay' }) 1363 api.nvim_buf_set_extmark( 1364 0, 1365 ns, 1366 0, 1367 91 + i, 1368 { virt_text = { { tostring(i), 'ErrorMsg' } }, virt_text_pos = 'overlay', virt_text_hide = true } 1369 ) 1370 end 1371 screen:expect { 1372 grid = [[ 1373 ababababababababababababababababababababab{4:01234567}| 1374 {4:89}abababababababababababababababababababa{4:012345678}| 1375 {4:9}babababababababababababababababababababababababab| 1376 ababababababababababababababababababababababababa^b| 1377 {1:~ }| 1378 | 1379 ]], 1380 } 1381 1382 command('set showbreak=++') 1383 screen:expect { 1384 grid = [[ 1385 ababababababababababababababababababababab{4:01234567}| 1386 {1:++}{4:89}abababababababababababababababababababa{4:0123456}| 1387 {1:++}{4:789}babababababababababababababababababababababab| 1388 {1:++}abababababababababababababababababababababababab| 1389 {1:++}ababa^b | 1390 | 1391 ]], 1392 } 1393 1394 feed('2gkvg0') 1395 screen:expect { 1396 grid = [[ 1397 ababababababababababababababababababababab{4:01234567}| 1398 {1:++}{4:89}abababababababababababababababababababa{4:0123456}| 1399 {1:++}^a{27:babab}ababababababababababababababababababababab| 1400 {1:++}abababababababababababababababababababababababab| 1401 {1:++}ababab | 1402 {24:-- VISUAL --} | 1403 ]], 1404 } 1405 1406 feed('o') 1407 screen:expect { 1408 grid = [[ 1409 ababababababababababababababababababababab{4:01234567}| 1410 {1:++}{4:89}abababababababababababababababababababa{4:0123456}| 1411 {1:++}{27:ababa}^bababababababababababababababababababababab| 1412 {1:++}abababababababababababababababababababababababab| 1413 {1:++}ababab | 1414 {24:-- VISUAL --} | 1415 ]], 1416 } 1417 1418 feed('gk') 1419 screen:expect { 1420 grid = [[ 1421 ababababababababababababababababababababab{4:01234567}| 1422 {1:++}{4:89}aba^b{27:ababababababababababababababababababababab}| 1423 {1:++}{27:a}{4:89}babababababababababababababababababababababab| 1424 {1:++}abababababababababababababababababababababababab| 1425 {1:++}ababab | 1426 {24:-- VISUAL --} | 1427 ]], 1428 } 1429 1430 feed('o') 1431 screen:expect { 1432 grid = [[ 1433 ababababababababababababababababababababab{4:01234567}| 1434 {1:++}{4:89}aba{27:bababababababababababababababababababababab}| 1435 {1:++}^a{4:89}babababababababababababababababababababababab| 1436 {1:++}abababababababababababababababababababababababab| 1437 {1:++}ababab | 1438 {24:-- VISUAL --} | 1439 ]], 1440 } 1441 1442 feed('<Esc>$') 1443 command('set number showbreak=') 1444 screen:expect { 1445 grid = [[ 1446 {2: 1 }ababababababababababababababababababababab{4:0123}| 1447 {2: }{4:456789}abababababababababababababababababababa{4:0}| 1448 {2: }{4:123456789}babababababababababababababababababab| 1449 {2: }ababababababababababababababababababababababab| 1450 {2: }abababababababa^b | 1451 | 1452 ]], 1453 } 1454 1455 command('set cpoptions+=n') 1456 screen:expect { 1457 grid = [[ 1458 {2: 1 }ababababababababababababababababababababab{4:0123}| 1459 {4:456789}abababababababababababababababababababa{4:01234}| 1460 {4:56789}babababababababababababababababababababababab| 1461 ababababababababababababababababababababababababab| 1462 aba^b | 1463 | 1464 ]], 1465 } 1466 1467 feed('0g$hi<Tab>') 1468 screen:expect { 1469 grid = [[ 1470 {2: 1 }ababababababababababababababababababababab{4:01} | 1471 {4:^23456789}abababababababababababababababababababa{4:0}| 1472 {4:123456789}babababababababababababababababababababab| 1473 ababababababababababababababababababababababababab| 1474 abababab | 1475 {24:-- INSERT --} | 1476 ]], 1477 } 1478 end) 1479 1480 it('virt_text_hide hides overlay virtual text when extmark is off-screen', function() 1481 screen:try_resize(50, 3) 1482 command('set nowrap') 1483 api.nvim_buf_set_lines(0, 0, -1, true, { '-- ' .. ('…'):rep(57) }) 1484 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { '?????', 'ErrorMsg' } }, virt_text_pos = 'overlay', virt_text_hide = true }) 1485 api.nvim_buf_set_extmark(0, ns, 0, 123, { virt_text = { { '!!!!!', 'ErrorMsg' } }, virt_text_pos = 'overlay', virt_text_hide = true }) 1486 screen:expect { 1487 grid = [[ 1488 {4:^?????}……………………………………………………………………………………………………{4:!!!!!}……| 1489 {1:~ }| 1490 | 1491 ]], 1492 } 1493 feed('40zl') 1494 screen:expect { 1495 grid = [[ 1496 ^………{4:!!!!!}……………………………… | 1497 {1:~ }| 1498 | 1499 ]], 1500 } 1501 feed('3zl') 1502 screen:expect { 1503 grid = [[ 1504 {4:^!!!!!}……………………………… | 1505 {1:~ }| 1506 | 1507 ]], 1508 } 1509 feed('7zl') 1510 screen:expect { 1511 grid = [[ 1512 ^………………………… | 1513 {1:~ }| 1514 | 1515 ]], 1516 } 1517 1518 command('set wrap smoothscroll') 1519 screen:expect { 1520 grid = [[ 1521 {4:?????}……………………………………………………………………………………………………{4:!!!!!}……| 1522 ^………………………… | 1523 | 1524 ]], 1525 } 1526 feed('<C-E>') 1527 screen:expect { 1528 grid = [[ 1529 {1:<<<}………………^… | 1530 {1:~ }| 1531 | 1532 ]], 1533 } 1534 screen:try_resize(40, 3) 1535 screen:expect { 1536 grid = [[ 1537 {1:<<<}{4:!!!!!}……………………………^… | 1538 {1:~ }| 1539 | 1540 ]], 1541 } 1542 feed('<C-Y>') 1543 screen:expect { 1544 grid = [[ 1545 {4:?????}……………………………………………………………………………………………| 1546 ………{4:!!!!!}……………………………^… | 1547 | 1548 ]], 1549 } 1550 end) 1551 1552 it('overlay virtual text works on and after a TAB #24022', function() 1553 screen:try_resize(40, 3) 1554 api.nvim_buf_set_lines(0, 0, -1, true, { '\t\tline 1' }) 1555 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Search' } }, virt_text_pos = 'overlay', hl_mode = 'combine' }) 1556 api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'BB', 'Search' } }, virt_text_pos = 'overlay', hl_mode = 'combine' }) 1557 api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'CC', 'Search' } }, virt_text_pos = 'overlay', hl_mode = 'combine' }) 1558 screen:expect { 1559 grid = [[ 1560 {34:AA} ^ {34:BB} {34:CC}ne 1 | 1561 {1:~ }| 1562 | 1563 ]], 1564 } 1565 command('setlocal list listchars=tab:<->') 1566 screen:expect { 1567 grid = [[ 1568 {35:^AA}{1:----->}{35:BB}{1:----->}{34:CC}ne 1 | 1569 {1:~ }| 1570 | 1571 ]], 1572 } 1573 end) 1574 1575 it('can have virtual text of overlay position and styling', function() 1576 insert(example_text) 1577 feed 'gg' 1578 1579 command 'set ft=lua' 1580 command 'syntax on' 1581 1582 screen:expect { 1583 grid = [[ 1584 {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} | 1585 {5:local} text, hl_id_cell, count {5:=} unpack(item) | 1586 {5:if} hl_id_cell {5:~=} {13:nil} {5:then} | 1587 hl_id {5:=} hl_id_cell | 1588 {5:end} | 1589 {5:for} _ {5:=} {13:1}, (count {5:or} {13:1}) {5:do} | 1590 {5:local} cell {5:=} line[colpos] | 1591 cell.text {5:=} text | 1592 cell.hl_id {5:=} hl_id | 1593 colpos {5:=} colpos{5:+}{13:1} | 1594 {5:end} | 1595 {5:end} | 1596 {1:~ }|*2 1597 | 1598 ]], 1599 } 1600 1601 command 'hi Blendy guibg=Red blend=30' 1602 command 'hi! Visual guifg=NONE guibg=LightGrey' 1603 api.nvim_buf_set_extmark( 1604 0, 1605 ns, 1606 1, 1607 5, 1608 { virt_text = { { 'blendy text - here', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'blend' } 1609 ) 1610 api.nvim_buf_set_extmark( 1611 0, 1612 ns, 1613 2, 1614 5, 1615 { virt_text = { { 'combining color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'combine' } 1616 ) 1617 api.nvim_buf_set_extmark( 1618 0, 1619 ns, 1620 3, 1621 5, 1622 { virt_text = { { 'replacing color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'replace' } 1623 ) 1624 1625 api.nvim_buf_set_extmark( 1626 0, 1627 ns, 1628 4, 1629 5, 1630 { virt_text = { { 'blendy text - here', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'blend', virt_text_hide = true } 1631 ) 1632 api.nvim_buf_set_extmark( 1633 0, 1634 ns, 1635 5, 1636 5, 1637 { virt_text = { { 'combining color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'combine', virt_text_hide = true } 1638 ) 1639 api.nvim_buf_set_extmark( 1640 0, 1641 ns, 1642 6, 1643 5, 1644 { virt_text = { { 'replacing color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'replace', virt_text_hide = true } 1645 ) 1646 1647 screen:expect { 1648 grid = [[ 1649 {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} | 1650 {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count {5:=} unpack(item) | 1651 {5:i}{12:c}{11:ombining col}{12:or} {13:nil} {5:then} | 1652 {11:replacing color}d_cell | 1653 {5:e}{8:bl}{7:endy}{10: }{7:text}{10: }{7:-}{10: }{7:here} | 1654 {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | 1655 {11:replacing color} line[colpos] | 1656 cell.text {5:=} text | 1657 cell.hl_id {5:=} hl_id | 1658 colpos {5:=} colpos{5:+}{13:1} | 1659 {5:end} | 1660 {5:end} | 1661 {1:~ }|*2 1662 | 1663 ]], 1664 } 1665 1666 feed 'V5G' 1667 screen:expect { 1668 grid = [[ 1669 {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} | 1670 {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} | 1671 {18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} | 1672 {18: }{11:replacing color}{18:d_cell} | 1673 {18: }{5:^e}{17:nd} | 1674 {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | 1675 {11:replacing color} line[colpos] | 1676 cell.text {5:=} text | 1677 cell.hl_id {5:=} hl_id | 1678 colpos {5:=} colpos{5:+}{13:1} | 1679 {5:end} | 1680 {5:end} | 1681 {1:~ }|*2 1682 {24:-- VISUAL LINE --} | 1683 ]], 1684 } 1685 1686 feed 'jj' 1687 screen:expect { 1688 grid = [[ 1689 {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} | 1690 {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} | 1691 {18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} | 1692 {18: }{11:replacing color}{18:d_cell} | 1693 {18: }{17:end} | 1694 {18: }{17:for}{18: _ }{17:=}{18: }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} | 1695 {18: }^ {18: }{17:local}{18: cell }{17:=}{18: line[colpos]} | 1696 cell.text {5:=} text | 1697 cell.hl_id {5:=} hl_id | 1698 colpos {5:=} colpos{5:+}{13:1} | 1699 {5:end} | 1700 {5:end} | 1701 {1:~ }|*2 1702 {24:-- VISUAL LINE --} | 1703 ]], 1704 } 1705 end) 1706 1707 it('can have virtual text of right_align and fixed win_col position', function() 1708 insert(example_text) 1709 feed 'gg' 1710 api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'Very', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' }) 1711 api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'VERY', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' }) 1712 api.nvim_buf_set_extmark(0, ns, 2, 10, { virt_text = { { 'Much', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' }) 1713 api.nvim_buf_set_extmark(0, ns, 2, 10, { virt_text = { { 'MUCH', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' }) 1714 api.nvim_buf_set_extmark(0, ns, 3, 14, { virt_text = { { 'Error', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' }) 1715 api.nvim_buf_set_extmark(0, ns, 3, 14, { virt_text = { { 'ERROR', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' }) 1716 api.nvim_buf_set_extmark(0, ns, 7, 21, { virt_text = { { '-', 'NonText' } }, virt_text_win_col = 4, hl_mode = 'blend' }) 1717 api.nvim_buf_set_extmark(0, ns, 7, 21, { virt_text = { { '-', 'NonText' } }, virt_text_pos = 'right_align', hl_mode = 'blend' }) 1718 -- empty virt_text should not change anything 1719 api.nvim_buf_set_extmark(0, ns, 8, 0, { virt_text = { { '' } }, virt_text_win_col = 14, hl_mode = 'blend' }) 1720 api.nvim_buf_set_extmark(0, ns, 8, 0, { virt_text = { { '' } }, virt_text_pos = 'right_align', hl_mode = 'blend' }) 1721 1722 screen:expect { 1723 grid = [[ 1724 ^for _,item in ipairs(items) do | 1725 local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| 1726 if hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1727 hl_id = hl_id_cell {4:Error} {4:ERROR}| 1728 end | 1729 for _ = 1, (count or 1) do | 1730 local cell = line[colpos] | 1731 {1:-} cell.text = text {1:-}| 1732 cell.hl_id = hl_id | 1733 colpos = colpos+1 | 1734 end | 1735 end | 1736 {1:~ }|*2 1737 | 1738 ]], 1739 } 1740 1741 feed '3G12|i<cr><esc>' 1742 screen:expect { 1743 grid = [[ 1744 for _,item in ipairs(items) do | 1745 local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| 1746 if hl_i {4:Much} {4:MUCH}| 1747 ^d_cell ~= nil then | 1748 hl_id = hl_id_cell {4:Error} {4:ERROR}| 1749 end | 1750 for _ = 1, (count or 1) do | 1751 local cell = line[colpos] | 1752 {1:-} cell.text = text {1:-}| 1753 cell.hl_id = hl_id | 1754 colpos = colpos+1 | 1755 end | 1756 end | 1757 {1:~ }| 1758 | 1759 ]], 1760 } 1761 1762 feed 'u:<cr>' 1763 screen:expect { 1764 grid = [[ 1765 for _,item in ipairs(items) do | 1766 local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| 1767 if hl_i^d_cell ~= nil then {4:Much} {4:MUCH}| 1768 hl_id = hl_id_cell {4:Error} {4:ERROR}| 1769 end | 1770 for _ = 1, (count or 1) do | 1771 local cell = line[colpos] | 1772 {1:-} cell.text = text {1:-}| 1773 cell.hl_id = hl_id | 1774 colpos = colpos+1 | 1775 end | 1776 end | 1777 {1:~ }|*2 1778 : | 1779 ]], 1780 } 1781 1782 feed '8|i<cr><esc>' 1783 screen:expect { 1784 grid = [[ 1785 for _,item in ipairs(items) do | 1786 local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| 1787 if | 1788 ^hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1789 hl_id = hl_id_cell {4:Error} {4:ERROR}| 1790 end | 1791 for _ = 1, (count or 1) do | 1792 local cell = line[colpos] | 1793 {1:-} cell.text = text {1:-}| 1794 cell.hl_id = hl_id | 1795 colpos = colpos+1 | 1796 end | 1797 end | 1798 {1:~ }| 1799 | 1800 ]], 1801 } 1802 1803 feed 'jI-- <esc>..........' 1804 screen:expect { 1805 grid = [[ 1806 for _,item in ipairs(items) do | 1807 local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| 1808 if | 1809 hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1810 --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}| 1811 l_id_cell | 1812 end | 1813 for _ = 1, (count or 1) do | 1814 local cell = line[colpos] | 1815 {1:-} cell.text = text {1:-}| 1816 cell.hl_id = hl_id | 1817 colpos = colpos+1 | 1818 end | 1819 end | 1820 | 1821 ]], 1822 } 1823 1824 api.nvim_buf_set_extmark(0, ns, 4, 50, { virt_text = { { 'EOL', 'NonText' } } }) 1825 screen:expect { 1826 grid = [[ 1827 for _,item in ipairs(items) do | 1828 local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| 1829 if | 1830 hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1831 --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}| 1832 l_id_cell {1:EOL} | 1833 end | 1834 for _ = 1, (count or 1) do | 1835 local cell = line[colpos] | 1836 {1:-} cell.text = text {1:-}| 1837 cell.hl_id = hl_id | 1838 colpos = colpos+1 | 1839 end | 1840 end | 1841 | 1842 ]], 1843 } 1844 1845 feed '.' 1846 screen:expect { 1847 grid = [[ 1848 for _,item in ipairs(items) do | 1849 local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| 1850 if | 1851 hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1852 --^ -- -- -- -- -- -- -- -- -- -- -- hl_id | 1853 = hl_id_cell {1:EOL} {4:Error} {4:ERROR}| 1854 end | 1855 for _ = 1, (count or 1) do | 1856 local cell = line[colpos] | 1857 {1:-} cell.text = text {1:-}| 1858 cell.hl_id = hl_id | 1859 colpos = colpos+1 | 1860 end | 1861 end | 1862 | 1863 ]], 1864 } 1865 1866 command 'set number' 1867 screen:expect { 1868 grid = [[ 1869 {2: 1 }for _,item in ipairs(items) do | 1870 {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}| 1871 {2: }m) | 1872 {2: 3 } if | 1873 {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1874 {2: 5 } --^ -- -- -- -- -- -- -- -- -- -- -- hl| 1875 {2: }_id = hl_id_cell {1:EOL} {4:Error} {4:ERROR}| 1876 {2: 6 } end | 1877 {2: 7 } for _ = 1, (count or 1) do | 1878 {2: 8 } local cell = line[colpos] | 1879 {2: 9 } {1:-} cell.text = text {1:-}| 1880 {2: 10 } cell.hl_id = hl_id | 1881 {2: 11 } colpos = colpos+1 | 1882 {2: 12 } end | 1883 | 1884 ]], 1885 } 1886 1887 command 'set cpoptions+=n' 1888 screen:expect { 1889 grid = [[ 1890 {2: 1 }for _,item in ipairs(items) do | 1891 {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}| 1892 m) | 1893 {2: 3 } if | 1894 {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1895 {2: 5 } --^ -- -- -- -- -- -- -- -- -- -- -- hl| 1896 _id = hl_id_cell {1:EOL} {4:Error} {4:ERROR}| 1897 {2: 6 } end | 1898 {2: 7 } for _ = 1, (count or 1) do | 1899 {2: 8 } local cell = line[colpos] | 1900 {2: 9 } {1:-} cell.text = text {1:-}| 1901 {2: 10 } cell.hl_id = hl_id | 1902 {2: 11 } colpos = colpos+1 | 1903 {2: 12 } end | 1904 | 1905 ]], 1906 } 1907 1908 command 'set cpoptions-=n nowrap' 1909 screen:expect { 1910 grid = [[ 1911 {2: 1 }for _,item in ipairs(items) do | 1912 {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}| 1913 {2: 3 } if | 1914 {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1915 {2: 5 } --^ -- -- -- -- -- -- --{4:Error}- -- {4:ERROR}| 1916 {2: 6 } end | 1917 {2: 7 } for _ = 1, (count or 1) do | 1918 {2: 8 } local cell = line[colpos] | 1919 {2: 9 } {1:-} cell.text = text {1:-}| 1920 {2: 10 } cell.hl_id = hl_id | 1921 {2: 11 } colpos = colpos+1 | 1922 {2: 12 } end | 1923 {2: 13 }end | 1924 {1:~ }| 1925 | 1926 ]], 1927 } 1928 1929 feed '12zl' 1930 screen:expect { 1931 grid = [[ 1932 {2: 1 }n ipairs(items) do | 1933 {2: 2 }xt, hl_id_cell, count = unpack({4:Very}) {4:VERY}| 1934 {2: 3 } | 1935 {2: 4 }= nil then {4:Much} {4:MUCH}| 1936 {2: 5 }^- -- -- -- -- -- -- -- -- -- --{4:Error}d = h{4:ERROR}| 1937 {2: 6 } | 1938 {2: 7 }1, (count or 1) do | 1939 {2: 8 }l cell = line[colpos] | 1940 {2: 9 }.tex{1:-} = text {1:-}| 1941 {2: 10 }.hl_id = hl_id | 1942 {2: 11 }os = colpos+1 | 1943 {2: 12 } | 1944 {2: 13 } | 1945 {1:~ }| 1946 | 1947 ]], 1948 } 1949 1950 feed('fhi<Tab>') 1951 screen:expect { 1952 grid = [[ 1953 {2: 1 }n ipairs(items) do | 1954 {2: 2 }xt, hl_id_cell, count = unpack({4:Very}) {4:VERY}| 1955 {2: 3 } | 1956 {2: 4 }= nil then {4:Much} {4:MUCH}| 1957 {2: 5 }- -- -- -- -- -- -- -- -- -- --{4:Error}^hl_id{4:ERROR}| 1958 {2: 6 } | 1959 {2: 7 }1, (count or 1) do | 1960 {2: 8 }l cell = line[colpos] | 1961 {2: 9 }.tex{1:-} = text {1:-}| 1962 {2: 10 }.hl_id = hl_id | 1963 {2: 11 }os = colpos+1 | 1964 {2: 12 } | 1965 {2: 13 } | 1966 {1:~ }| 1967 {24:-- INSERT --} | 1968 ]], 1969 } 1970 1971 feed('<Esc>0') 1972 screen:expect { 1973 grid = [[ 1974 {2: 1 }for _,item in ipairs(items) do | 1975 {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}| 1976 {2: 3 } if | 1977 {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}| 1978 {2: 5 }^ -- -- -- -- -- -- -- --{4:Error}- -- {4:ERROR}| 1979 {2: 6 } end | 1980 {2: 7 } for _ = 1, (count or 1) do | 1981 {2: 8 } local cell = line[colpos] | 1982 {2: 9 } {1:-} cell.text = text {1:-}| 1983 {2: 10 } cell.hl_id = hl_id | 1984 {2: 11 } colpos = colpos+1 | 1985 {2: 12 } end | 1986 {2: 13 }end | 1987 {1:~ }| 1988 | 1989 ]], 1990 } 1991 end) 1992 1993 it('virtual text win_col out of window does not break display #25645', function() 1994 screen:try_resize(51, 6) 1995 command('vnew') 1996 api.nvim_buf_set_lines(0, 0, -1, false, { string.rep('a', 50) }) 1997 screen:expect { 1998 grid = [[ 1999 ^aaaaaaaaaaaaaaaaaaaaaaaaa│ | 2000 aaaaaaaaaaaaaaaaaaaaaaaaa│{1:~ }| 2001 {1:~ }│{1:~ }|*2 2002 {41:[No Name] [+] }{40:[No Name] }| 2003 | 2004 ]], 2005 } 2006 local extmark_opts = { virt_text_win_col = 35, virt_text = { { ' ', 'Comment' } } } 2007 api.nvim_buf_set_extmark(0, ns, 0, 0, extmark_opts) 2008 screen:expect_unchanged() 2009 assert_alive() 2010 end) 2011 2012 it('can have virtual text on folded line', function() 2013 insert([[ 2014 11111 2015 22222 2016 33333]]) 2017 command('1,2fold') 2018 screen:try_resize(50, 3) 2019 feed('zb') 2020 -- XXX: the behavior of overlay virtual text at non-zero column is strange: 2021 -- 1. With 'wrap' it is never shown. 2022 -- 2. With 'nowrap' it is shown only if the extmark is hidden before leftcol. 2023 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Underlined' } }, hl_mode = 'combine', virt_text_pos = 'overlay' }) 2024 api.nvim_buf_set_extmark(0, ns, 0, 5, { virt_text = { { 'BB', 'Underlined' } }, hl_mode = 'combine', virt_text_win_col = 10 }) 2025 api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'CC', 'Underlined' } }, hl_mode = 'combine', virt_text_pos = 'right_align' }) 2026 screen:expect { 2027 grid = [[ 2028 {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}| 2029 3333^3 | 2030 | 2031 ]], 2032 } 2033 command('set nowrap') 2034 screen:expect_unchanged() 2035 feed('zl') 2036 screen:expect { 2037 grid = [[ 2038 {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}| 2039 333^3 | 2040 | 2041 ]], 2042 } 2043 feed('zl') 2044 screen:expect { 2045 grid = [[ 2046 {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}| 2047 33^3 | 2048 | 2049 ]], 2050 } 2051 feed('zl') 2052 screen:expect { 2053 grid = [[ 2054 {29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}| 2055 3^3 | 2056 | 2057 ]], 2058 } 2059 end) 2060 2061 it('virtual text works below diff filler lines', function() 2062 screen:try_resize(53, 8) 2063 insert([[ 2064 aaaaa 2065 bbbbb 2066 ccccc 2067 ddddd 2068 eeeee]]) 2069 command('rightbelow vnew') 2070 insert([[ 2071 bbbbb 2072 ccccc 2073 ddddd 2074 eeeee]]) 2075 command('windo diffthis') 2076 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Underlined' } }, virt_text_pos = 'overlay' }) 2077 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB', 'Underlined' } }, virt_text_win_col = 10 }) 2078 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'CC', 'Underlined' } }, virt_text_pos = 'right_align' }) 2079 screen:expect { 2080 grid = [[ 2081 {37: }{38:aaaaa }│{37: }{39:------------------------}| 2082 {37: }bbbbb │{37: }{28:AA}bbb {28:BB} {28:CC}| 2083 {37: }ccccc │{37: }ccccc | 2084 {37: }ddddd │{37: }ddddd | 2085 {37: }eeeee │{37: }eeee^e | 2086 {1:~ }│{1:~ }| 2087 {40:[No Name] [+] }{41:[No Name] [+] }| 2088 | 2089 ]], 2090 } 2091 command('windo set wrap') 2092 screen:expect_unchanged() 2093 end) 2094 2095 it('can have virtual text which combines foreground and background groups', function() 2096 screen:try_resize(20, 5) 2097 2098 screen:set_default_attr_ids { 2099 [1] = { bold = true, foreground = Screen.colors.Blue }, 2100 [2] = { background = tonumber('0x123456'), foreground = tonumber('0xbbbbbb') }, 2101 [3] = { background = tonumber('0x123456'), foreground = tonumber('0xcccccc') }, 2102 [4] = { background = tonumber('0x234567'), foreground = tonumber('0xbbbbbb') }, 2103 [5] = { background = tonumber('0x234567'), foreground = tonumber('0xcccccc') }, 2104 [6] = { bold = true, foreground = tonumber('0xcccccc'), background = tonumber('0x234567') }, 2105 } 2106 2107 exec [[ 2108 hi BgOne guibg=#123456 2109 hi BgTwo guibg=#234567 2110 hi FgEin guifg=#bbbbbb 2111 hi FgZwei guifg=#cccccc 2112 hi VeryBold gui=bold 2113 ]] 2114 2115 insert('##') 2116 local vt = { 2117 { 'a', { 'BgOne', 'FgEin' } }, 2118 { 'b', { 'BgOne', 'FgZwei' } }, 2119 { 'c', { 'BgTwo', 'FgEin' } }, 2120 { 'd', { 'BgTwo', 'FgZwei' } }, 2121 { 'X', { 'BgTwo', 'FgZwei', 'VeryBold' } }, 2122 } 2123 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'eol' }) 2124 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'right_align' }) 2125 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'inline' }) 2126 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { vt, vt } }) 2127 screen:expect { 2128 grid = [[ 2129 {2:a}{3:b}{4:c}{5:d}{6:X}#^# {2:a}{3:b}{4:c}{5:d}{6:X} {2:a}{3:b}{4:c}{5:d}{6:X}| 2130 {2:a}{3:b}{4:c}{5:d}{6:X} |*2 2131 {1:~ }| 2132 | 2133 ]], 2134 } 2135 end) 2136 2137 it('does not crash when deleting a cleared buffer #15212', function() 2138 exec_lua [[ 2139 ns = vim.api.nvim_create_namespace("myplugin") 2140 vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {virt_text = {{"a"}}, end_col = 0}) 2141 ]] 2142 screen:expect { 2143 grid = [[ 2144 ^ a | 2145 {1:~ }|*13 2146 | 2147 ]], 2148 } 2149 2150 exec_lua [[ 2151 vim.api.nvim_buf_clear_namespace(0, ns, 0, -1) 2152 vim.cmd("bdelete") 2153 ]] 2154 screen:expect { 2155 grid = [[ 2156 ^ | 2157 {1:~ }|*13 2158 | 2159 ]], 2160 } 2161 assert_alive() 2162 end) 2163 2164 it('conceal with conceal char #19007', function() 2165 screen:try_resize(50, 5) 2166 insert('foo\n') 2167 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 0, end_row = 2, conceal = 'X' }) 2168 command('set conceallevel=2') 2169 screen:expect([[ 2170 {26:X} | 2171 ^ | 2172 {1:~ }|*2 2173 | 2174 ]]) 2175 command('set conceallevel=1') 2176 screen:expect_unchanged() 2177 2178 eq('conceal char has to be printable', pcall_err(api.nvim_buf_set_extmark, 0, ns, 0, 0, { end_col = 0, end_row = 2, conceal = '\255' })) 2179 end) 2180 2181 it('conceal with composed conceal char', function() 2182 screen:try_resize(50, 5) 2183 insert('foo\n') 2184 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 0, end_row = 2, conceal = 'ẍ̲' }) 2185 command('set conceallevel=2') 2186 screen:expect([[ 2187 {26:ẍ̲} | 2188 ^ | 2189 {1:~ }|*2 2190 | 2191 ]]) 2192 command('set conceallevel=1') 2193 screen:expect_unchanged() 2194 2195 -- this is rare, but could happen. Save at least the first codepoint 2196 api.nvim__invalidate_glyph_cache() 2197 screen:expect { 2198 grid = [[ 2199 {26:x} | 2200 ^ | 2201 {1:~ }|*2 2202 | 2203 ]], 2204 } 2205 end) 2206 2207 it('conceal without conceal char #24782', function() 2208 screen:try_resize(50, 5) 2209 insert('foobar\n') 2210 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, conceal = '' }) 2211 command('set listchars=conceal:?') 2212 command('let &conceallevel=1') 2213 screen:expect([[ 2214 {26:?}bar | 2215 ^ | 2216 {1:~ }|*2 2217 | 2218 ]]) 2219 command('let &conceallevel=2') 2220 screen:expect([[ 2221 bar | 2222 ^ | 2223 {1:~ }|*2 2224 | 2225 ]]) 2226 end) 2227 2228 it('conceal works just before truncated double-width char #21486', function() 2229 screen:try_resize(40, 4) 2230 api.nvim_buf_set_lines(0, 0, -1, true, { '', ('a'):rep(37) .. '<>古' }) 2231 api.nvim_buf_set_extmark(0, ns, 1, 37, { end_col = 39, conceal = '' }) 2232 command('setlocal conceallevel=2') 2233 screen:expect { 2234 grid = [[ 2235 ^ | 2236 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:>} | 2237 古 | 2238 | 2239 ]], 2240 } 2241 feed('j') 2242 screen:expect { 2243 grid = [[ 2244 | 2245 ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<>{1:>}| 2246 古 | 2247 | 2248 ]], 2249 } 2250 end) 2251 2252 it('redraws properly when adding/removing conceal on non-current line', function() 2253 screen:try_resize(50, 5) 2254 api.nvim_buf_set_lines(0, 0, -1, true, { 'abcd', 'efgh', 'ijkl', 'mnop' }) 2255 command('setlocal conceallevel=2') 2256 screen:expect { 2257 grid = [[ 2258 ^abcd | 2259 efgh | 2260 ijkl | 2261 mnop | 2262 | 2263 ]], 2264 } 2265 api.nvim_buf_set_extmark(0, ns, 2, 1, { end_col = 3, conceal = '' }) 2266 screen:expect { 2267 grid = [[ 2268 ^abcd | 2269 efgh | 2270 il | 2271 mnop | 2272 | 2273 ]], 2274 } 2275 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2276 screen:expect { 2277 grid = [[ 2278 ^abcd | 2279 efgh | 2280 ijkl | 2281 mnop | 2282 | 2283 ]], 2284 } 2285 end) 2286 2287 it('avoids redraw issue #20651', function() 2288 exec_lua [[ 2289 vim.cmd.normal'10oXXX' 2290 vim.cmd.normal'gg' 2291 local ns = vim.api.nvim_create_namespace('ns') 2292 2293 local bufnr = vim.api.nvim_create_buf(false, true) 2294 vim.api.nvim_open_win(bufnr, false, { relative = 'win', height = 1, width = 1, row = 0, col = 0 }) 2295 2296 vim.api.nvim_create_autocmd('CursorMoved', { callback = function() 2297 local row = vim.api.nvim_win_get_cursor(0)[1] - 1 2298 vim.api.nvim_buf_set_extmark(0, ns, row, 0, { id = 1 }) 2299 vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {}) 2300 vim.schedule(function() 2301 vim.api.nvim_buf_set_extmark(0, ns, row, 0, { 2302 id = 1, 2303 virt_text = {{'HELLO', 'Normal'}}, 2304 }) 2305 end) 2306 end 2307 }) 2308 ]] 2309 2310 for _ = 1, 3 do 2311 vim.uv.sleep(10) 2312 feed 'j' 2313 end 2314 2315 screen:expect { 2316 grid = [[ 2317 {44: } | 2318 XXX |*2 2319 ^XXX HELLO | 2320 XXX |*7 2321 {1:~ }|*3 2322 | 2323 ]], 2324 } 2325 end) 2326 2327 it('underline attribute with higher priority takes effect #22371', function() 2328 screen:try_resize(50, 3) 2329 insert('aaabbbaaa') 2330 exec([[ 2331 hi TestUL gui=underline guifg=Blue 2332 hi TestUC gui=undercurl guisp=Red 2333 hi TestBold gui=bold 2334 ]]) 2335 screen:set_default_attr_ids({ 2336 [0] = { bold = true, foreground = Screen.colors.Blue }, 2337 [1] = { underline = true, foreground = Screen.colors.Blue }, 2338 [2] = { undercurl = true, special = Screen.colors.Red }, 2339 [3] = { underline = true, foreground = Screen.colors.Blue, special = Screen.colors.Red }, 2340 [4] = { undercurl = true, foreground = Screen.colors.Blue, special = Screen.colors.Red }, 2341 [5] = { bold = true, underline = true, foreground = Screen.colors.Blue }, 2342 [6] = { bold = true, undercurl = true, special = Screen.colors.Red }, 2343 }) 2344 2345 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 20 }) 2346 api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUC', priority = 30 }) 2347 screen:expect([[ 2348 {1:aaa}{4:bbb}{1:aa^a} | 2349 {0:~ }| 2350 | 2351 ]]) 2352 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2353 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 20 }) 2354 api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUL', priority = 30 }) 2355 screen:expect([[ 2356 {2:aaa}{3:bbb}{2:aa^a} | 2357 {0:~ }| 2358 | 2359 ]]) 2360 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2361 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 30 }) 2362 api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUC', priority = 20 }) 2363 screen:expect([[ 2364 {1:aaa}{3:bbb}{1:aa^a} | 2365 {0:~ }| 2366 | 2367 ]]) 2368 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2369 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 30 }) 2370 api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUL', priority = 20 }) 2371 screen:expect([[ 2372 {2:aaa}{4:bbb}{2:aa^a} | 2373 {0:~ }| 2374 | 2375 ]]) 2376 2377 -- When only one highlight group has an underline attribute, it should always take effect. 2378 for _, d in ipairs({ -5, 5 }) do 2379 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2380 screen:expect([[ 2381 aaabbbaa^a | 2382 {0:~ }| 2383 | 2384 ]]) 2385 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 25 + d }) 2386 api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 25 - d }) 2387 screen:expect([[ 2388 {1:aaa}{5:bbb}{1:aa^a} | 2389 {0:~ }| 2390 | 2391 ]]) 2392 end 2393 for _, d in ipairs({ -5, 5 }) do 2394 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2395 screen:expect([[ 2396 aaabbbaa^a | 2397 {0:~ }| 2398 | 2399 ]]) 2400 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 25 + d }) 2401 api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 25 - d }) 2402 screen:expect([[ 2403 {2:aaa}{6:bbb}{2:aa^a} | 2404 {0:~ }| 2405 | 2406 ]]) 2407 end 2408 end) 2409 2410 it('highlight is combined with syntax and sign linehl #20004', function() 2411 screen:try_resize(50, 3) 2412 insert([[ 2413 function Func() 2414 end]]) 2415 feed('gg') 2416 command('set ft=lua') 2417 command('syntax on') 2418 command('hi default MyMark guibg=LightGrey') 2419 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, hl_mode = 'combine', hl_group = 'MyMark' }) 2420 command('hi default MyLine gui=underline') 2421 command('sign define CurrentLine linehl=MyLine') 2422 fn.sign_place(6, 'Test', 'CurrentLine', '', { lnum = 1 }) 2423 screen:expect { 2424 grid = [[ 2425 {30:^fun}{31:ction}{32: Func() }| 2426 {6:end} | 2427 | 2428 ]], 2429 } 2430 end) 2431 2432 it('highlight can combine multiple groups', function() 2433 screen:try_resize(50, 3) 2434 command('hi Group1 guibg=Red guifg=Red guisp=Red') 2435 command('hi Group2 guibg=Blue guifg=Blue') 2436 command('hi Group3 guibg=Green') 2437 insert([[example text]]) 2438 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = {} }) 2439 screen:expect([[ 2440 example tex^t | 2441 {1:~ }| 2442 | 2443 ]]) 2444 2445 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2446 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1' } }) 2447 screen:expect([[ 2448 {45:example tex^t} | 2449 {1:~ }| 2450 | 2451 ]]) 2452 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2453 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2' } }) 2454 screen:expect([[ 2455 {46:example tex^t} | 2456 {1:~ }| 2457 | 2458 ]]) 2459 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2460 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2', 'Group3' }, hl_eol = true }) 2461 screen:expect([[ 2462 {47:example tex^t }| 2463 {1:~ }| 2464 | 2465 ]]) 2466 2467 eq( 2468 'Invalid hl_group: hl_group item', 2469 pcall_err(api.nvim_buf_set_extmark, 0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2', { 'fail' } }, hl_eol = true }) 2470 ) 2471 end) 2472 2473 it('highlight works after TAB with sidescroll #14201', function() 2474 screen:try_resize(50, 3) 2475 command('set nowrap') 2476 api.nvim_buf_set_lines(0, 0, -1, true, { '\tword word word word' }) 2477 api.nvim_buf_set_extmark(0, ns, 0, 1, { end_col = 3, hl_group = 'ErrorMsg' }) 2478 screen:expect { 2479 grid = [[ 2480 ^ {4:wo}rd word word word | 2481 {1:~ }| 2482 | 2483 ]], 2484 } 2485 feed('7zl') 2486 screen:expect { 2487 grid = [[ 2488 {4:^wo}rd word word word | 2489 {1:~ }| 2490 | 2491 ]], 2492 } 2493 feed('zl') 2494 screen:expect { 2495 grid = [[ 2496 {4:^wo}rd word word word | 2497 {1:~ }| 2498 | 2499 ]], 2500 } 2501 feed('zl') 2502 screen:expect { 2503 grid = [[ 2504 {4:^o}rd word word word | 2505 {1:~ }| 2506 | 2507 ]], 2508 } 2509 end) 2510 2511 it('highlights the beginning of a TAB char correctly #23734', function() 2512 screen:try_resize(50, 3) 2513 api.nvim_buf_set_lines(0, 0, -1, true, { 'this is the\ttab' }) 2514 api.nvim_buf_set_extmark(0, ns, 0, 11, { end_col = 15, hl_group = 'ErrorMsg' }) 2515 screen:expect { 2516 grid = [[ 2517 ^this is the{4: tab} | 2518 {1:~ }| 2519 | 2520 ]], 2521 } 2522 2523 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2524 api.nvim_buf_set_extmark(0, ns, 0, 12, { end_col = 15, hl_group = 'ErrorMsg' }) 2525 screen:expect { 2526 grid = [[ 2527 ^this is the {4:tab} | 2528 {1:~ }| 2529 | 2530 ]], 2531 } 2532 end) 2533 2534 it('highlight applies to a full TAB on line with matches #20885', function() 2535 screen:try_resize(50, 3) 2536 api.nvim_buf_set_lines(0, 0, -1, true, { '\t-- match1', ' -- match2' }) 2537 fn.matchadd('NonText', 'match') 2538 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, end_col = 0, hl_group = 'Search' }) 2539 api.nvim_buf_set_extmark(0, ns, 1, 0, { end_row = 2, end_col = 0, hl_group = 'Search' }) 2540 screen:expect { 2541 grid = [[ 2542 {34: ^ -- }{35:match}{34:1} | 2543 {34: -- }{35:match}{34:2} | 2544 | 2545 ]], 2546 } 2547 end) 2548 2549 it('highlight applies to a full TAB in visual block mode', function() 2550 screen:try_resize(50, 8) 2551 command('hi! Visual guifg=NONE guibg=LightGrey') 2552 api.nvim_buf_set_lines(0, 0, -1, true, { 'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf' }) 2553 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 5, end_col = 0, hl_group = 'Underlined' }) 2554 screen:expect([[ 2555 {28:^asdf} | 2556 {28: asdf} |*3 2557 {28:asdf} | 2558 {1:~ }|*2 2559 | 2560 ]]) 2561 feed('<C-V>Gll') 2562 screen:expect([[ 2563 {29:asd}{28:f} | 2564 {29: }{28: asdf} |*3 2565 {29:as}{28:^df} | 2566 {1:~ }|*2 2567 {24:-- VISUAL BLOCK --} | 2568 ]]) 2569 end) 2570 2571 it('highlight works properly with multibyte text and spell #26771', function() 2572 insert('口口\n') 2573 screen:try_resize(50, 3) 2574 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, hl_group = 'Search' }) 2575 screen:expect([[ 2576 {34:口}口 | 2577 ^ | 2578 | 2579 ]]) 2580 command('setlocal spell') 2581 screen:expect([[ 2582 {43:口}{42:口} | 2583 ^ | 2584 | 2585 ]]) 2586 end) 2587 2588 it('supports multiline highlights', function() 2589 insert(example_text) 2590 feed 'gg' 2591 for _, i in ipairs { 1, 2, 3, 5, 6, 7 } do 2592 for _, j in ipairs { 2, 5, 10, 15 } do 2593 api.nvim_buf_set_extmark(0, ns, i, j, { end_col = j + 2, hl_group = 'NonText' }) 2594 end 2595 end 2596 screen:expect { 2597 grid = [[ 2598 ^for _,item in ipairs(items) do | 2599 {1: }l{1:oc}al {1:te}xt,{1: h}l_id_cell, count = unpack(item) | 2600 {1: }i{1:f }hl_{1:id}_ce{1:ll} ~= nil then | 2601 {1: } {1: } hl{1:_i}d ={1: h}l_id_cell | 2602 end | 2603 {1: }f{1:or} _ {1:= }1, {1:(c}ount or 1) do | 2604 {1: } {1: } lo{1:ca}l c{1:el}l = line[colpos] | 2605 {1: } {1: } ce{1:ll}.te{1:xt} = text | 2606 cell.hl_id = hl_id | 2607 colpos = colpos+1 | 2608 end | 2609 end | 2610 {1:~ }|*2 2611 | 2612 ]], 2613 } 2614 feed '5<c-e>' 2615 screen:expect { 2616 grid = [[ 2617 ^ {1: }f{1:or} _ {1:= }1, {1:(c}ount or 1) do | 2618 {1: } {1: } lo{1:ca}l c{1:el}l = line[colpos] | 2619 {1: } {1: } ce{1:ll}.te{1:xt} = text | 2620 cell.hl_id = hl_id | 2621 colpos = colpos+1 | 2622 end | 2623 end | 2624 {1:~ }|*7 2625 | 2626 ]], 2627 } 2628 2629 api.nvim_buf_set_extmark(0, ns, 1, 0, { end_line = 8, end_col = 10, hl_group = 'ErrorMsg' }) 2630 screen:expect { 2631 grid = [[ 2632 {4:^ }{36: }{4:f}{36:or}{4: _ }{36:= }{4:1, }{36:(c}{4:ount or 1) do} | 2633 {4: }{36: }{4: }{36: }{4: lo}{36:ca}{4:l c}{36:el}{4:l = line[colpos]} | 2634 {4: }{36: }{4: }{36: }{4: ce}{36:ll}{4:.te}{36:xt}{4: = text} | 2635 {4: ce}ll.hl_id = hl_id | 2636 colpos = colpos+1 | 2637 end | 2638 end | 2639 {1:~ }|*7 2640 | 2641 ]], 2642 } 2643 end) 2644 2645 local function with_undo_restore(val) 2646 screen:try_resize(50, 5) 2647 insert(example_text) 2648 feed 'gg' 2649 api.nvim_buf_set_extmark(0, ns, 0, 6, { end_col = 13, hl_group = 'NonText', undo_restore = val }) 2650 screen:expect { 2651 grid = [[ 2652 ^for _,{1:item in} ipairs(items) do | 2653 local text, hl_id_cell, count = unpack(item) | 2654 if hl_id_cell ~= nil then | 2655 hl_id = hl_id_cell | 2656 | 2657 ]], 2658 } 2659 2660 api.nvim_buf_set_text(0, 0, 4, 0, 8, { '' }) 2661 screen:expect { 2662 grid = [[ 2663 ^for {1:em in} ipairs(items) do | 2664 local text, hl_id_cell, count = unpack(item) | 2665 if hl_id_cell ~= nil then | 2666 hl_id = hl_id_cell | 2667 | 2668 ]], 2669 } 2670 end 2671 2672 it('highlights do reapply to restored text after delete', function() 2673 with_undo_restore(true) -- also default behavior 2674 2675 command('silent undo') 2676 screen:expect { 2677 grid = [[ 2678 ^for _,{1:item in} ipairs(items) do | 2679 local text, hl_id_cell, count = unpack(item) | 2680 if hl_id_cell ~= nil then | 2681 hl_id = hl_id_cell | 2682 | 2683 ]], 2684 } 2685 end) 2686 2687 it("highlights don't reapply to restored text after delete with undo_restore=false", function() 2688 with_undo_restore(false) 2689 2690 command('silent undo') 2691 screen:expect { 2692 grid = [[ 2693 ^for _,it{1:em in} ipairs(items) do | 2694 local text, hl_id_cell, count = unpack(item) | 2695 if hl_id_cell ~= nil then | 2696 hl_id = hl_id_cell | 2697 | 2698 ]], 2699 } 2700 2701 eq({ 2702 { 2703 1, 2704 0, 2705 8, 2706 { 2707 end_col = 13, 2708 end_right_gravity = false, 2709 end_row = 0, 2710 hl_eol = false, 2711 hl_group = 'NonText', 2712 undo_restore = false, 2713 ns_id = ns, 2714 priority = 4096, 2715 right_gravity = true, 2716 }, 2717 }, 2718 }, api.nvim_buf_get_extmarks(0, ns, { 0, 0 }, { 0, -1 }, { details = true })) 2719 end) 2720 2721 it('virtual text works with rightleft', function() 2722 screen:try_resize(50, 3) 2723 insert('abcdefghijklmn') 2724 feed('0') 2725 command('set rightleft') 2726 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'EOL', 'Underlined' } } }) 2727 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'right_align', 'Underlined' } }, virt_text_pos = 'right_align' }) 2728 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'win_col', 'Underlined' } }, virt_text_win_col = 20 }) 2729 api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'overlayed', 'Underlined' } }, virt_text_pos = 'overlay' }) 2730 screen:expect { 2731 grid = [[ 2732 {28:ngila_thgir} {28:loc_niw} {28:LOE} nml{28:deyalrevo}b^a| 2733 {1: ~}| 2734 | 2735 ]], 2736 } 2737 2738 insert(('#'):rep(32)) 2739 feed('0') 2740 screen:expect { 2741 grid = [[ 2742 {28:ngila_tdeyalrevo}ba#####{28:loc_niw}###################^#| 2743 {1: ~}| 2744 | 2745 ]], 2746 } 2747 2748 insert(('#'):rep(16)) 2749 feed('0') 2750 screen:expect { 2751 grid = [[ 2752 {28:ngila_thgir}############{28:loc_niw}###################^#| 2753 {28:LOE} nml{28:deyalrevo}| 2754 | 2755 ]], 2756 } 2757 2758 insert('###') 2759 feed('0') 2760 screen:expect { 2761 grid = [[ 2762 #################################################^#| 2763 {28:ngila_thgir} {28:loc_niw} {28:LOE} nml{28:deyalrevo}ba#| 2764 | 2765 ]], 2766 } 2767 2768 command('set number') 2769 screen:expect { 2770 grid = [[ 2771 #############################################^#{2: 1 }| 2772 {28:ngila_thgir} {28:loc_niw} nml{28:deyalrevo}ba#####{2: }| 2773 | 2774 ]], 2775 } 2776 2777 command('set cpoptions+=n') 2778 screen:expect { 2779 grid = [[ 2780 #############################################^#{2: 1 }| 2781 {28:ngila_thgir} {28:loc_niw} nml{28:deyalrevo}ba#####| 2782 | 2783 ]], 2784 } 2785 end) 2786 2787 it('virtual text overwrites double-width char properly', function() 2788 screen:try_resize(50, 3) 2789 insert('abcdefghij口klmnopqrstu口vwx口yz') 2790 feed('0') 2791 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { '!!!!!', 'Underlined' } }, virt_text_win_col = 11 }) 2792 screen:expect { 2793 grid = [[ 2794 ^abcdefghij {28:!!!!!}opqrstu口vwx口yz | 2795 {1:~ }| 2796 | 2797 ]], 2798 } 2799 feed('8x') 2800 screen:expect { 2801 grid = [[ 2802 ^ij口klmnopq{28:!!!!!} vwx口yz | 2803 {1:~ }| 2804 | 2805 ]], 2806 } 2807 feed('3l5x') 2808 screen:expect { 2809 grid = [[ 2810 ij口^pqrstu {28:!!!!!} yz | 2811 {1:~ }| 2812 | 2813 ]], 2814 } 2815 feed('5x') 2816 screen:expect { 2817 grid = [[ 2818 ij口^u口vwx {28:!!!!!} | 2819 {1:~ }| 2820 | 2821 ]], 2822 } 2823 end) 2824 2825 it('virtual text blending space does not overwrite double-width char', function() 2826 screen:try_resize(50, 3) 2827 insert('abcdefghij口klmnopqrstu口vwx口yz') 2828 feed('0') 2829 command('hi Blendy guibg=Red blend=30') 2830 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { ' ! ! ', 'Blendy' } }, virt_text_win_col = 8, hl_mode = 'blend' }) 2831 screen:expect { 2832 grid = [[ 2833 ^abcdefgh{10:i}{7:!}{10:口}{7:!}{10:l}mnopqrstu口vwx口yz | 2834 {1:~ }| 2835 | 2836 ]], 2837 } 2838 feed('x') 2839 screen:expect { 2840 grid = [[ 2841 ^bcdefghi{10:j}{7:!}{10: k}{7:!}{10:m}nopqrstu口vwx口yz | 2842 {1:~ }| 2843 | 2844 ]], 2845 } 2846 feed('x') 2847 screen:expect { 2848 grid = [[ 2849 ^cdefghij{10: }{7:!}{10:kl}{7:!}{10:n}opqrstu口vwx口yz | 2850 {1:~ }| 2851 | 2852 ]], 2853 } 2854 feed('x') 2855 screen:expect { 2856 grid = [[ 2857 ^defghij口{7:!}{10:lm}{7:!}{10:o}pqrstu口vwx口yz | 2858 {1:~ }| 2859 | 2860 ]], 2861 } 2862 feed('7x') 2863 screen:expect { 2864 grid = [[ 2865 ^口klmnop{10:q}{7:!}{10:st}{7:!}{10:口}vwx口yz | 2866 {1:~ }| 2867 | 2868 ]], 2869 } 2870 end) 2871 2872 it('virtual text works with double-width char and rightleft', function() 2873 screen:try_resize(50, 3) 2874 insert('abcdefghij口klmnopqrstu口vwx口yz') 2875 feed('0') 2876 command('set rightleft') 2877 screen:expect { 2878 grid = [[ 2879 zy口xwv口utsrqponmlk口jihgfedcb^a| 2880 {1: ~}| 2881 | 2882 ]], 2883 } 2884 api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'overlayed', 'Underlined' } }, virt_text_pos = 'overlay' }) 2885 api.nvim_buf_set_extmark(0, ns, 0, 14, { virt_text = { { '古', 'Underlined' } }, virt_text_pos = 'overlay' }) 2886 api.nvim_buf_set_extmark(0, ns, 0, 20, { virt_text = { { '\t', 'Underlined' } }, virt_text_pos = 'overlay' }) 2887 api.nvim_buf_set_extmark(0, ns, 0, 29, { virt_text = { { '古', 'Underlined' } }, virt_text_pos = 'overlay' }) 2888 screen:expect { 2889 grid = [[ 2890 zy {28:古}wv {28: }qpon{28:古}k {28:deyalrevo}b^a| 2891 {1: ~}| 2892 | 2893 ]], 2894 } 2895 end) 2896 2897 it('virtual text is drawn correctly after delete and undo #27368', function() 2898 insert('aaa\nbbb\nccc\nddd\neee') 2899 command('vsplit') 2900 api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'EOL' } } }) 2901 feed('3gg') 2902 screen:expect { 2903 grid = [[ 2904 aaa │aaa | 2905 bbb │bbb | 2906 ^ccc EOL │ccc EOL | 2907 ddd │ddd | 2908 eee │eee | 2909 {1:~ }│{1:~ }|*8 2910 {41:[No Name] [+] }{40:[No Name] [+] }| 2911 | 2912 ]], 2913 } 2914 feed('dd') 2915 screen:expect { 2916 grid = [[ 2917 aaa │aaa | 2918 bbb │bbb | 2919 ^ddd EOL │ddd EOL | 2920 eee │eee | 2921 {1:~ }│{1:~ }|*9 2922 {41:[No Name] [+] }{40:[No Name] [+] }| 2923 | 2924 ]], 2925 } 2926 command('silent undo') 2927 screen:expect { 2928 grid = [[ 2929 aaa │aaa | 2930 bbb │bbb | 2931 ^ccc EOL │ccc EOL | 2932 ddd │ddd | 2933 eee │eee | 2934 {1:~ }│{1:~ }|*8 2935 {41:[No Name] [+] }{40:[No Name] [+] }| 2936 | 2937 ]], 2938 } 2939 end) 2940 2941 it('virtual text does not crash with blend, conceal and wrap #27836', function() 2942 screen:try_resize(50, 3) 2943 insert(('a'):rep(45) .. '|hidden|' .. ('b'):rep(45)) 2944 command('syntax match test /|hidden|/ conceal') 2945 command('set conceallevel=2 concealcursor=n') 2946 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'FOO' } }, virt_text_pos = 'right_align', hl_mode = 'blend' }) 2947 screen:expect { 2948 grid = [[ 2949 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa FOO| 2950 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b | 2951 | 2952 ]], 2953 } 2954 end) 2955 2956 it('works with both hl_group and sign_hl_group', function() 2957 screen:try_resize(50, 3) 2958 screen:add_extra_attr_ids({ 2959 [100] = { background = Screen.colors.WebGray, foreground = Screen.colors.Blue, bold = true }, 2960 }) 2961 insert('abcdefghijklmn') 2962 api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S', sign_hl_group = 'NonText', hl_group = 'Error', end_col = 14 }) 2963 screen:expect([[ 2964 {100:S }{9:abcdefghijklm^n} | 2965 {1:~ }| 2966 | 2967 ]]) 2968 end) 2969 2970 it('virt_text_repeat_linebreak repeats virtual text on wrapped lines', function() 2971 screen:try_resize(40, 5) 2972 api.nvim_set_option_value('breakindent', true, {}) 2973 insert(example_text) 2974 api.nvim_buf_set_extmark( 2975 0, 2976 ns, 2977 1, 2978 0, 2979 { virt_text = { { '│', 'NonText' } }, virt_text_pos = 'overlay', virt_text_repeat_linebreak = true } 2980 ) 2981 api.nvim_buf_set_extmark( 2982 0, 2983 ns, 2984 1, 2985 3, 2986 { virt_text = { { '│', 'NonText' } }, virt_text_pos = 'overlay', virt_text_repeat_linebreak = true } 2987 ) 2988 command('norm gg') 2989 screen:expect { 2990 grid = [[ 2991 ^for _,item in ipairs(items) do | 2992 {1:│} {1:│}local text, hl_id_cell, count = unpa| 2993 {1:│} {1:│}ck(item) | 2994 if hl_id_cell ~= nil then | 2995 | 2996 ]], 2997 } 2998 api.nvim_buf_clear_namespace(0, ns, 0, -1) 2999 api.nvim_buf_set_extmark( 3000 0, 3001 ns, 3002 1, 3003 0, 3004 { virt_text = { { '│', 'NonText' } }, virt_text_repeat_linebreak = true, virt_text_win_col = 0 } 3005 ) 3006 api.nvim_buf_set_extmark( 3007 0, 3008 ns, 3009 1, 3010 0, 3011 { virt_text = { { '│', 'NonText' } }, virt_text_repeat_linebreak = true, virt_text_win_col = 2 } 3012 ) 3013 screen:expect { 3014 grid = [[ 3015 ^for _,item in ipairs(items) do | 3016 {1:│} {1:│} local text, hl_id_cell, count = unpa| 3017 {1:│} {1:│} ck(item) | 3018 if hl_id_cell ~= nil then | 3019 | 3020 ]], 3021 } 3022 end) 3023 3024 it('supports URLs', function() 3025 insert(example_text) 3026 3027 local url1 = 'https://example.com' 3028 local url2 = 'http://127.0.0.1' 3029 3030 screen:add_extra_attr_ids { 3031 u = { url = url1 }, 3032 uh = { url = url2, background = Screen.colors.Yellow }, 3033 } 3034 3035 api.nvim_buf_set_extmark(0, ns, 1, 4, { 3036 end_col = 14, 3037 url = url1, 3038 }) 3039 api.nvim_buf_set_extmark(0, ns, 2, 4, { 3040 end_col = 17, 3041 hl_group = 'Search', 3042 url = url2, 3043 }) 3044 3045 screen:expect([[ 3046 for _,item in ipairs(items) do | 3047 {u:local text}, hl_id_cell, count = unpack(item) | 3048 {uh:if hl_id_cell} ~= nil then | 3049 hl_id = hl_id_cell | 3050 end | 3051 for _ = 1, (count or 1) do | 3052 local cell = line[colpos] | 3053 cell.text = text | 3054 cell.hl_id = hl_id | 3055 colpos = colpos+1 | 3056 end | 3057 en^d | 3058 {1:~ }|*2 3059 | 3060 ]]) 3061 end) 3062 3063 it('can replace marks in place with different decorations #27211', function() 3064 local mark = api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'foo', 'ErrorMsg' } } } }) 3065 screen:expect { 3066 grid = [[ 3067 ^ | 3068 {4:foo} | 3069 {1:~ }|*12 3070 | 3071 ]], 3072 } 3073 3074 api.nvim_buf_set_extmark(0, ns, 0, 0, { 3075 id = mark, 3076 virt_text = { { 'testing', 'NonText' } }, 3077 virt_text_pos = 'inline', 3078 }) 3079 screen:expect { 3080 grid = [[ 3081 {1:^testing} | 3082 {1:~ }|*13 3083 | 3084 ]], 3085 } 3086 3087 api.nvim_buf_del_extmark(0, ns, mark) 3088 screen:expect { 3089 grid = [[ 3090 ^ | 3091 {1:~ }|*13 3092 | 3093 ]], 3094 } 3095 3096 n.assert_alive() 3097 end) 3098 3099 it('priority ordering of overlay or win_col virtual text at same position', function() 3100 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'A' } }, virt_text_pos = 'overlay', priority = 100 }) 3101 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'A' } }, virt_text_win_col = 30, priority = 100 }) 3102 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB' } }, virt_text_pos = 'overlay', priority = 90 }) 3103 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB' } }, virt_text_win_col = 30, priority = 90 }) 3104 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'CCC' } }, virt_text_pos = 'overlay', priority = 80 }) 3105 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'CCC' } }, virt_text_win_col = 30, priority = 80 }) 3106 screen:expect([[ 3107 ^ABC ABC | 3108 {1:~ }|*13 3109 | 3110 ]]) 3111 end) 3112 3113 it('priority ordering of inline and non-inline virtual text at same char', function() 3114 insert(('?'):rep(40) .. ('!'):rep(30)) 3115 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'A' } }, virt_text_pos = 'overlay', priority = 10 }) 3116 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'a' } }, virt_text_win_col = 15, priority = 10 }) 3117 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'BBBB' } }, virt_text_pos = 'inline', priority = 15 }) 3118 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'C' } }, virt_text_pos = 'overlay', priority = 20 }) 3119 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'c' } }, virt_text_win_col = 17, priority = 20 }) 3120 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'DDDD' } }, virt_text_pos = 'inline', priority = 25 }) 3121 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'E' } }, virt_text_pos = 'overlay', priority = 30 }) 3122 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'e' } }, virt_text_win_col = 19, priority = 30 }) 3123 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'FFFF' } }, virt_text_pos = 'inline', priority = 35 }) 3124 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'G' } }, virt_text_pos = 'overlay', priority = 40 }) 3125 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'g' } }, virt_text_win_col = 21, priority = 40 }) 3126 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'HHHH' } }, virt_text_pos = 'inline', priority = 45 }) 3127 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'I' } }, virt_text_pos = 'overlay', priority = 50 }) 3128 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'i' } }, virt_text_win_col = 23, priority = 50 }) 3129 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'JJJJ' } }, virt_text_pos = 'inline', priority = 55 }) 3130 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'K' } }, virt_text_pos = 'overlay', priority = 60 }) 3131 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'k' } }, virt_text_win_col = 25, priority = 60 }) 3132 screen:expect([[ 3133 ???????????????a?c?e????????????????????ABBBCDDDEF| 3134 FFGHHHIJJJK!!!!!!!!!!g!i!k!!!!!!!!!!!!!^! | 3135 {1:~ }|*12 3136 | 3137 ]]) 3138 feed('02x$') 3139 screen:expect([[ 3140 ???????????????a?c?e??????????????????ABBBCDDDEFFF| 3141 GHHHIJJJK!!!!!!!!!!!!g!i!k!!!!!!!!!!!^! | 3142 {1:~ }|*12 3143 | 3144 ]]) 3145 feed('02x$') 3146 screen:expect([[ 3147 ???????????????a?c?e?g??????????????ABBBCDDDEFFFGH| 3148 HHIJJJK!!!!!!!!!!!!!!!!i!k!!!!!!!!!^! | 3149 {1:~ }|*12 3150 | 3151 ]]) 3152 feed('02x$') 3153 screen:expect([[ 3154 ???????????????a?c?e?g????????????ABBBCDDDEFFFGHHH| 3155 IJJJK!!!!!!!!!!!!!!!!!!i!k!!!!!!!^! | 3156 {1:~ }|*12 3157 | 3158 ]]) 3159 command('set nowrap') 3160 feed('0') 3161 screen:expect([[ 3162 ^???????????????a?c?e?g?i?k????????ABBBCDDDEFFFGHHH| 3163 {1:~ }|*13 3164 | 3165 ]]) 3166 feed('2x') 3167 screen:expect([[ 3168 ^???????????????a?c?e?g?i?k??????ABBBCDDDEFFFGHHHIJ| 3169 {1:~ }|*13 3170 | 3171 ]]) 3172 feed('2x') 3173 screen:expect([[ 3174 ^???????????????a?c?e?g?i?k????ABBBCDDDEFFFGHHHIJJJ| 3175 {1:~ }|*13 3176 | 3177 ]]) 3178 feed('2x') 3179 screen:expect([[ 3180 ^???????????????a?c?e?g?i?k??ABBBCDDDEFFFGHHHIJJJK!| 3181 {1:~ }|*13 3182 | 3183 ]]) 3184 end) 3185 3186 it('conceal_lines', function() 3187 insert(example_text) 3188 exec('set number conceallevel=3') 3189 feed('ggj') 3190 local not_concealed = { 3191 grid = [[ 3192 {2: 1 }for _,item in ipairs(items) do | 3193 {2: 2 }^ local text, hl_id_cell, count = unpack(ite| 3194 {2: }m) | 3195 {2: 3 } if hl_id_cell ~= nil then | 3196 {2: 4 } hl_id = hl_id_cell | 3197 {2: 5 } end | 3198 {2: 6 } for _ = 1, (count or 1) do | 3199 {2: 7 } local cell = line[colpos] | 3200 {2: 8 } cell.text = text | 3201 {2: 9 } cell.hl_id = hl_id | 3202 {2: 10 } colpos = colpos+1 | 3203 {2: 11 } end | 3204 {2: 12 }end | 3205 {1:~ }| 3206 | 3207 ]], 3208 } 3209 screen:expect(not_concealed) 3210 api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' }) 3211 screen:expect_unchanged() 3212 feed('j') 3213 local concealed = { 3214 grid = [[ 3215 {2: 1 }for _,item in ipairs(items) do | 3216 {2: 3 }^ if hl_id_cell ~= nil then | 3217 {2: 4 } hl_id = hl_id_cell | 3218 {2: 5 } end | 3219 {2: 6 } for _ = 1, (count or 1) do | 3220 {2: 7 } local cell = line[colpos] | 3221 {2: 8 } cell.text = text | 3222 {2: 9 } cell.hl_id = hl_id | 3223 {2: 10 } colpos = colpos+1 | 3224 {2: 11 } end | 3225 {2: 12 }end | 3226 {1:~ }|*3 3227 | 3228 ]], 3229 } 3230 screen:expect(concealed) 3231 feed('k') 3232 screen:expect(not_concealed) 3233 exec('set concealcursor=n') 3234 screen:expect(concealed) 3235 api.nvim_buf_set_extmark(0, ns, 3, 0, { conceal_lines = '' }) 3236 screen:expect({ 3237 grid = [[ 3238 {2: 1 }for _,item in ipairs(items) do | 3239 {2: 3 }^ if hl_id_cell ~= nil then | 3240 {2: 5 } end | 3241 {2: 6 } for _ = 1, (count or 1) do | 3242 {2: 7 } local cell = line[colpos] | 3243 {2: 8 } cell.text = text | 3244 {2: 9 } cell.hl_id = hl_id | 3245 {2: 10 } colpos = colpos+1 | 3246 {2: 11 } end | 3247 {2: 12 }end | 3248 {1:~ }|*4 3249 | 3250 ]], 3251 }) 3252 feed('kjj') 3253 screen:expect_unchanged() 3254 api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' }) 3255 feed('kjjjC') 3256 screen:expect({ 3257 grid = [[ 3258 {2: 1 }for _,item in ipairs(items) do | 3259 {2: 3 } if hl_id_cell ~= nil then | 3260 {2: 5 }^ | 3261 {2: 6 } for _ = 1, (count or 1) do | 3262 {2: 7 } local cell = line[colpos] | 3263 {2: 8 } cell.text = text | 3264 {2: 9 } cell.hl_id = hl_id | 3265 {2: 10 } colpos = colpos+1 | 3266 {2: 11 } end | 3267 {2: 12 }end | 3268 {1:~ }|*4 3269 {24:-- INSERT --} | 3270 ]], 3271 }) 3272 feed('<esc>') 3273 screen:expect({ 3274 grid = [[ 3275 {2: 1 }for _,item in ipairs(items) do | 3276 {2: 3 } if hl_id_cell ~= nil then | 3277 {2: 6 }^ for _ = 1, (count or 1) do | 3278 {2: 7 } local cell = line[colpos] | 3279 {2: 8 } cell.text = text | 3280 {2: 9 } cell.hl_id = hl_id | 3281 {2: 10 } colpos = colpos+1 | 3282 {2: 11 } end | 3283 {2: 12 }end | 3284 {1:~ }|*5 3285 | 3286 ]], 3287 }) 3288 feed('kji') 3289 screen:expect({ 3290 grid = [[ 3291 {2: 1 }for _,item in ipairs(items) do | 3292 {2: 3 } if hl_id_cell ~= nil then | 3293 {2: 5 }^ | 3294 {2: 6 } for _ = 1, (count or 1) do | 3295 {2: 7 } local cell = line[colpos] | 3296 {2: 8 } cell.text = text | 3297 {2: 9 } cell.hl_id = hl_id | 3298 {2: 10 } colpos = colpos+1 | 3299 {2: 11 } end | 3300 {2: 12 }end | 3301 {1:~ }|*4 3302 {24:-- INSERT --} | 3303 ]], 3304 }) 3305 feed('conceal text') 3306 screen:expect({ 3307 grid = [[ 3308 {2: 1 }for _,item in ipairs(items) do | 3309 {2: 3 } if hl_id_cell ~= nil then | 3310 {2: 5 }conceal text^ | 3311 {2: 6 } for _ = 1, (count or 1) do | 3312 {2: 7 } local cell = line[colpos] | 3313 {2: 8 } cell.text = text | 3314 {2: 9 } cell.hl_id = hl_id | 3315 {2: 10 } colpos = colpos+1 | 3316 {2: 11 } end | 3317 {2: 12 }end | 3318 {1:~ }|*4 3319 {24:-- INSERT --} | 3320 ]], 3321 }) 3322 feed('<esc>') 3323 screen:expect({ 3324 grid = [[ 3325 {2: 1 }for _,item in ipairs(items) do | 3326 {2: 3 } if hl_id_cell ~= nil then | 3327 {2: 6 } for _ =^ 1, (count or 1) do | 3328 {2: 7 } local cell = line[colpos] | 3329 {2: 8 } cell.text = text | 3330 {2: 9 } cell.hl_id = hl_id | 3331 {2: 10 } colpos = colpos+1 | 3332 {2: 11 } end | 3333 {2: 12 }end | 3334 {1:~ }|*5 3335 | 3336 ]], 3337 }) 3338 feed('ggzfj') 3339 screen:expect({ 3340 grid = [[ 3341 {2: 1 }{33:^+-- 2 lines: for _,item in ipairs(items) do··}| 3342 {2: 3 } if hl_id_cell ~= nil then | 3343 {2: 6 } for _ = 1, (count or 1) do | 3344 {2: 7 } local cell = line[colpos] | 3345 {2: 8 } cell.text = text | 3346 {2: 9 } cell.hl_id = hl_id | 3347 {2: 10 } colpos = colpos+1 | 3348 {2: 11 } end | 3349 {2: 12 }end | 3350 {1:~ }|*5 3351 | 3352 ]], 3353 }) 3354 feed('j') 3355 screen:expect({ 3356 grid = [[ 3357 {2: 1 }{33:+-- 2 lines: for _,item in ipairs(items) do··}| 3358 {2: 3 }^ if hl_id_cell ~= nil then | 3359 {2: 6 } for _ = 1, (count or 1) do | 3360 {2: 7 } local cell = line[colpos] | 3361 {2: 8 } cell.text = text | 3362 {2: 9 } cell.hl_id = hl_id | 3363 {2: 10 } colpos = colpos+1 | 3364 {2: 11 } end | 3365 {2: 12 }end | 3366 {1:~ }|*5 3367 | 3368 ]], 3369 }) 3370 feed('ggzdjzfj') 3371 screen:expect({ 3372 grid = [[ 3373 {2: 1 }for _,item in ipairs(items) do | 3374 {2: 6 }^ for _ = 1, (count or 1) do | 3375 {2: 7 } local cell = line[colpos] | 3376 {2: 8 } cell.text = text | 3377 {2: 9 } cell.hl_id = hl_id | 3378 {2: 10 } colpos = colpos+1 | 3379 {2: 11 } end | 3380 {2: 12 }end | 3381 {1:~ }|*6 3382 | 3383 ]], 3384 }) 3385 feed('jj') 3386 screen:expect({ 3387 grid = [[ 3388 {2: 1 }^for _,item in ipairs(items) do | 3389 {2: 6 } for _ = 1, (count or 1) do | 3390 {2: 7 } local cell = line[colpos] | 3391 {2: 8 } cell.text = text | 3392 {2: 9 } cell.hl_id = hl_id | 3393 {2: 10 } colpos = colpos+1 | 3394 {2: 11 } end | 3395 {2: 12 }end | 3396 {1:~ }|*6 3397 | 3398 ]], 3399 }) 3400 -- Below virtual line belonging to line above concealed line is drawn. 3401 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'line 1 below' } } } }) 3402 -- Above virtual line belonging to concealed line isn't. 3403 api.nvim_buf_set_extmark(0, ns, 1, 0, { 3404 virt_lines = { { { 'line 2 above' } } }, 3405 virt_lines_above = true, 3406 }) 3407 screen:expect([[ 3408 {2: 1 }for _,item in ipairs(items) do | 3409 {2: }line 1 below | 3410 {2: 6 }^ for _ = 1, (count or 1) do | 3411 {2: 7 } local cell = line[colpos] | 3412 {2: 8 } cell.text = text | 3413 {2: 9 } cell.hl_id = hl_id | 3414 {2: 10 } colpos = colpos+1 | 3415 {2: 11 } end | 3416 {2: 12 }end | 3417 {1:~ }|*5 3418 | 3419 ]]) 3420 -- w_lines.wl_lastlnum values are valid 3421 command('set relativenumber concealcursor=') 3422 api.nvim_buf_clear_namespace(0, ns, 0, -1) 3423 api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' }) 3424 api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' }) 3425 feed('zE') 3426 screen:expect([[ 3427 {2: 4 }for _,item in ipairs(items) do | 3428 {2: 2 } if hl_id_cell ~= nil then | 3429 {2: 1 } hl_id = hl_id_cell | 3430 {2:5 }^conceal text | 3431 {2: 1 } for _ = 1, (count or 1) do | 3432 {2: 2 } local cell = line[colpos] | 3433 {2: 3 } cell.text = text | 3434 {2: 4 } cell.hl_id = hl_id | 3435 {2: 5 } colpos = colpos+1 | 3436 {2: 6 } end | 3437 {2: 7 }end | 3438 {1:~ }|*3 3439 | 3440 ]]) 3441 feed('jj') 3442 screen:expect([[ 3443 {2: 6 }for _,item in ipairs(items) do | 3444 {2: 4 } if hl_id_cell ~= nil then | 3445 {2: 3 } hl_id = hl_id_cell | 3446 {2: 1 } for _ = 1, (count or 1) do | 3447 {2:7 }^ local cell = line[colpos] | 3448 {2: 1 } cell.text = text | 3449 {2: 2 } cell.hl_id = hl_id | 3450 {2: 3 } colpos = colpos+1 | 3451 {2: 4 } end | 3452 {2: 5 }end | 3453 {1:~ }|*4 3454 | 3455 ]]) 3456 -- Correct relativenumber for line below concealed line #33694 3457 feed('4Gk') 3458 screen:expect([[ 3459 {2: 2 }for _,item in ipairs(items) do | 3460 {2:3 } if h^l_id_cell ~= nil then | 3461 {2: 1 } hl_id = hl_id_cell | 3462 {2: 3 } for _ = 1, (count or 1) do | 3463 {2: 4 } local cell = line[colpos] | 3464 {2: 5 } cell.text = text | 3465 {2: 6 } cell.hl_id = hl_id | 3466 {2: 7 } colpos = colpos+1 | 3467 {2: 8 } end | 3468 {2: 9 }end | 3469 {1:~ }|*4 3470 | 3471 ]]) 3472 -- Also with above virtual line #32744 3473 command('set nornu') 3474 api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'virt_below 4' } } } }) 3475 feed('6G') 3476 screen:expect([[ 3477 {2: 1 }for _,item in ipairs(items) do | 3478 {2: 3 } if hl_id_cell ~= nil then | 3479 {2: 4 } hl_id = hl_id_cell | 3480 {2: }virt_below 4 | 3481 {2: 6 } ^for _ = 1, (count or 1) do | 3482 {2: 7 } local cell = line[colpos] | 3483 {2: 8 } cell.text = text | 3484 {2: 9 } cell.hl_id = hl_id | 3485 {2: 10 } colpos = colpos+1 | 3486 {2: 11 } end | 3487 {2: 12 }end | 3488 {1:~ }|*3 3489 | 3490 ]]) 3491 feed('j') 3492 screen:expect([[ 3493 {2: 1 }for _,item in ipairs(items) do | 3494 {2: 3 } if hl_id_cell ~= nil then | 3495 {2: 4 } hl_id = hl_id_cell | 3496 {2: }virt_below 4 | 3497 {2: 6 } for _ = 1, (count or 1) do | 3498 {2: 7 } ^ local cell = line[colpos] | 3499 {2: 8 } cell.text = text | 3500 {2: 9 } cell.hl_id = hl_id | 3501 {2: 10 } colpos = colpos+1 | 3502 {2: 11 } end | 3503 {2: 12 }end | 3504 {1:~ }|*3 3505 | 3506 ]]) 3507 -- Even when virtual line is added as line is concealed #32762 3508 feed('5G') 3509 api.nvim_buf_clear_namespace(0, ns, 3, 4) 3510 feed('j') 3511 api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'virt_below 4' } } } }) 3512 screen:expect([[ 3513 {2: 1 }for _,item in ipairs(items) do | 3514 {2: 3 } if hl_id_cell ~= nil then | 3515 {2: 4 } hl_id = hl_id_cell | 3516 {2: }virt_below 4 | 3517 {2: 6 }^ for _ = 1, (count or 1) do | 3518 {2: 7 } local cell = line[colpos] | 3519 {2: 8 } cell.text = text | 3520 {2: 9 } cell.hl_id = hl_id | 3521 {2: 10 } colpos = colpos+1 | 3522 {2: 11 } end | 3523 {2: 12 }end | 3524 {1:~ }|*3 3525 | 3526 ]]) 3527 -- No scrolling for concealed topline #33033 3528 api.nvim_buf_clear_namespace(0, ns, 0, -1) 3529 api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_lines_above = true, virt_lines = { { { 'virt_above 2' } } } }) 3530 api.nvim_buf_set_extmark(0, ns, 0, 0, { conceal_lines = '' }) 3531 feed('ggjj') 3532 screen:expect([[ 3533 {2: }virt_above 2 | 3534 {2: 2 } local text, hl_id_cell, count = unpack(ite| 3535 {2: }m) | 3536 {2: 3 }^ if hl_id_cell ~= nil then | 3537 {2: 4 } hl_id = hl_id_cell | 3538 {2: 5 }conceal text | 3539 {2: 6 } for _ = 1, (count or 1) do | 3540 {2: 7 } local cell = line[colpos] | 3541 {2: 8 } cell.text = text | 3542 {2: 9 } cell.hl_id = hl_id | 3543 {2: 10 } colpos = colpos+1 | 3544 {2: 11 } end | 3545 {2: 12 }end | 3546 {1:~ }| 3547 | 3548 ]]) 3549 -- No asymmetric topline for <C-E><C-Y> #33182 3550 feed('4<C-E>') 3551 exec('set concealcursor=n') 3552 api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' }) 3553 eq(5, n.fn.line('w0')) 3554 feed('<C-E><C-Y>') 3555 eq(5, n.fn.line('w0')) 3556 end) 3557 3558 it('conceal_lines not checking on invalid row #36057', function() 3559 exec_lua(function() 3560 vim.fn.setline(1, { 'foo', 'bar', 'baz' }) 3561 vim.api.nvim_command('set conceallevel=3 scrolloff=3') 3562 vim.api.nvim_open_win(0, true, { width = 1, height = 1, relative = 'editor', row = 0, col = 0 }) 3563 vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' }) 3564 vim.api.nvim__redraw({ flush = true }) 3565 end) 3566 n.assert_alive() 3567 end) 3568 3569 it('redraws the line from which a left gravity mark has moved #27369', function() 3570 fn.setline(1, { 'aaa', 'bbb', 'ccc', 'ddd' }) 3571 api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'foo' } }, right_gravity = false }) 3572 feed('yyp') 3573 screen:expect([[ 3574 aaa | 3575 ^aaa foo | 3576 bbb | 3577 ccc | 3578 ddd | 3579 {1:~ }|*9 3580 | 3581 ]]) 3582 end) 3583 3584 it('redraws extmark that starts and ends outside the screen', function() 3585 local lines = vim.split(('1'):rep(20), '', { plain = true }) 3586 api.nvim_buf_set_lines(0, 0, -1, true, lines) 3587 api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'ErrorMsg', end_row = 19, end_col = 0 }) 3588 screen:expect({ 3589 grid = [[ 3590 {4:^1} | 3591 {4:1} |*13 3592 | 3593 ]], 3594 }) 3595 feed('<C-e>') 3596 -- Newly visible line should also have the highlight. 3597 screen:expect({ 3598 grid = [[ 3599 {4:^1} | 3600 {4:1} |*13 3601 | 3602 ]], 3603 }) 3604 end) 3605 3606 it('line("w$", win) considers conceal_lines', function() 3607 api.nvim_buf_set_lines(0, 0, -1, true, { 'line 1', 'line 2', 'line 3' }) 3608 api.nvim_buf_set_extmark(0, ns, 0, 0, { conceal_lines = '' }) -- conceal line 1 3609 3610 local win = exec_lua(function() 3611 local provider_ns = vim.api.nvim_create_namespace('test_f_line') 3612 _G.line_w_dollar = {} 3613 vim.api.nvim_set_decoration_provider(provider_ns, { 3614 on_start = function() 3615 for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do 3616 table.insert(_G.line_w_dollar, { win, vim.fn.line('w$', win) }) 3617 end 3618 end, 3619 }) 3620 3621 local win = vim.api.nvim_open_win(0, false, { 3622 relative = 'editor', 3623 width = 20, 3624 height = 1, 3625 row = 0, 3626 col = 0, 3627 border = 'single', 3628 }) 3629 vim.api.nvim_set_option_value('conceallevel', 2, { scope = 'local', win = win }) 3630 3631 return win 3632 end) 3633 3634 local line_w_dollar = exec_lua('return _G.line_w_dollar') 3635 for _, win_line in ipairs(line_w_dollar) do 3636 if win_line[1] == win then 3637 eq(2, win_line[2]) 3638 end 3639 end 3640 end) 3641 end) 3642 3643 describe('decorations: inline virtual text', function() 3644 local screen ---@type test.functional.ui.screen 3645 local ns ---@type integer 3646 before_each(function() 3647 clear() 3648 screen = Screen.new(50, 3) 3649 screen:set_default_attr_ids { 3650 [1] = { bold = true, foreground = Screen.colors.Blue }, 3651 [2] = { foreground = Screen.colors.Brown }, 3652 [3] = { bold = true, foreground = Screen.colors.SeaGreen }, 3653 [4] = { background = Screen.colors.Red1, foreground = Screen.colors.Gray100 }, 3654 [5] = { background = Screen.colors.Red1, bold = true }, 3655 [6] = { foreground = Screen.colors.DarkCyan }, 3656 [7] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black }, 3657 [8] = { bold = true }, 3658 [9] = { background = Screen.colors.Plum1 }, 3659 [10] = { foreground = Screen.colors.SlateBlue }, 3660 [11] = { blend = 30, background = Screen.colors.Red1 }, 3661 [12] = { background = Screen.colors.Yellow }, 3662 [13] = { reverse = true }, 3663 [14] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.LightMagenta }, 3664 [15] = { bold = true, reverse = true }, 3665 [16] = { foreground = Screen.colors.Red }, 3666 [17] = { background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue }, 3667 [18] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Red }, 3668 [19] = { background = Screen.colors.Yellow, foreground = Screen.colors.SlateBlue }, 3669 [20] = { background = Screen.colors.LightGrey, foreground = Screen.colors.SlateBlue }, 3670 [21] = { reverse = true, foreground = Screen.colors.SlateBlue }, 3671 [22] = { background = Screen.colors.Gray90 }, 3672 [23] = { background = Screen.colors.Gray90, foreground = Screen.colors.Blue, bold = true }, 3673 } 3674 3675 ns = api.nvim_create_namespace 'test' 3676 end) 3677 3678 it('works', function() 3679 screen:try_resize(50, 10) 3680 insert(example_text) 3681 feed 'gg' 3682 screen:expect { 3683 grid = [[ 3684 ^for _,item in ipairs(items) do | 3685 local text, hl_id_cell, count = unpack(item) | 3686 if hl_id_cell ~= nil then | 3687 hl_id = hl_id_cell | 3688 end | 3689 for _ = 1, (count or 1) do | 3690 local cell = line[colpos] | 3691 cell.text = text | 3692 cell.hl_id = hl_id | 3693 | 3694 ]], 3695 } 3696 3697 api.nvim_buf_set_extmark(0, ns, 1, 14, { virt_text = { { ': ', 'Special' }, { 'string', 'Type' } }, virt_text_pos = 'inline' }) 3698 screen:expect { 3699 grid = [[ 3700 ^for _,item in ipairs(items) do | 3701 local text{10:: }{3:string}, hl_id_cell, count = unpack| 3702 (item) | 3703 if hl_id_cell ~= nil then | 3704 hl_id = hl_id_cell | 3705 end | 3706 for _ = 1, (count or 1) do | 3707 local cell = line[colpos] | 3708 cell.text = text | 3709 | 3710 ]], 3711 } 3712 3713 screen:try_resize(55, 10) 3714 screen:expect { 3715 grid = [[ 3716 ^for _,item in ipairs(items) do | 3717 local text{10:: }{3:string}, hl_id_cell, count = unpack(item| 3718 ) | 3719 if hl_id_cell ~= nil then | 3720 hl_id = hl_id_cell | 3721 end | 3722 for _ = 1, (count or 1) do | 3723 local cell = line[colpos] | 3724 cell.text = text | 3725 | 3726 ]], 3727 } 3728 3729 screen:try_resize(56, 10) 3730 screen:expect { 3731 grid = [[ 3732 ^for _,item in ipairs(items) do | 3733 local text{10:: }{3:string}, hl_id_cell, count = unpack(item)| 3734 if hl_id_cell ~= nil then | 3735 hl_id = hl_id_cell | 3736 end | 3737 for _ = 1, (count or 1) do | 3738 local cell = line[colpos] | 3739 cell.text = text | 3740 cell.hl_id = hl_id | 3741 | 3742 ]], 3743 } 3744 end) 3745 3746 it('works with 0-width chunk', function() 3747 screen:try_resize(50, 10) 3748 insert(example_text) 3749 feed 'gg' 3750 screen:expect { 3751 grid = [[ 3752 ^for _,item in ipairs(items) do | 3753 local text, hl_id_cell, count = unpack(item) | 3754 if hl_id_cell ~= nil then | 3755 hl_id = hl_id_cell | 3756 end | 3757 for _ = 1, (count or 1) do | 3758 local cell = line[colpos] | 3759 cell.text = text | 3760 cell.hl_id = hl_id | 3761 | 3762 ]], 3763 } 3764 3765 api.nvim_buf_set_extmark(0, ns, 0, 5, { virt_text = { { '' }, { '' } }, virt_text_pos = 'inline' }) 3766 api.nvim_buf_set_extmark(0, ns, 1, 14, { virt_text = { { '' }, { ': ', 'Special' } }, virt_text_pos = 'inline' }) 3767 api.nvim_buf_set_extmark(0, ns, 1, 48, { virt_text = { { '' }, { '' } }, virt_text_pos = 'inline' }) 3768 screen:expect { 3769 grid = [[ 3770 ^for _,item in ipairs(items) do | 3771 local text{10:: }, hl_id_cell, count = unpack(item)| 3772 if hl_id_cell ~= nil then | 3773 hl_id = hl_id_cell | 3774 end | 3775 for _ = 1, (count or 1) do | 3776 local cell = line[colpos] | 3777 cell.text = text | 3778 cell.hl_id = hl_id | 3779 | 3780 ]], 3781 } 3782 3783 api.nvim_buf_set_extmark(0, ns, 1, 14, { virt_text = { { '' }, { 'string', 'Type' } }, virt_text_pos = 'inline' }) 3784 feed('V') 3785 screen:expect { 3786 grid = [[ 3787 ^f{7:or _,item in ipairs(items) do} | 3788 local text{10:: }{3:string}, hl_id_cell, count = unpack| 3789 (item) | 3790 if hl_id_cell ~= nil then | 3791 hl_id = hl_id_cell | 3792 end | 3793 for _ = 1, (count or 1) do | 3794 local cell = line[colpos] | 3795 cell.text = text | 3796 {8:-- VISUAL LINE --} | 3797 ]], 3798 } 3799 3800 feed('<Esc>jf,') 3801 screen:expect { 3802 grid = [[ 3803 for _,item in ipairs(items) do | 3804 local text{10:: }{3:string}^, hl_id_cell, count = unpack| 3805 (item) | 3806 if hl_id_cell ~= nil then | 3807 hl_id = hl_id_cell | 3808 end | 3809 for _ = 1, (count or 1) do | 3810 local cell = line[colpos] | 3811 cell.text = text | 3812 | 3813 ]], 3814 } 3815 end) 3816 3817 it('Normal mode "gM" command works properly', function() 3818 command([[call setline(1, '123456789')]]) 3819 api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' }) 3820 api.nvim_buf_set_extmark(0, ns, 0, 7, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' }) 3821 feed('gM') 3822 screen:expect { 3823 grid = [[ 3824 12{10:bbb}34^567{10:bbb}89 | 3825 {1:~ }| 3826 | 3827 ]], 3828 } 3829 end) 3830 3831 local function test_normal_gj_gk() 3832 screen:try_resize(60, 6) 3833 command([[call setline(1, repeat([repeat('a', 55)], 2))]]) 3834 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(10), 'Special' } }, virt_text_pos = 'inline' }) 3835 api.nvim_buf_set_extmark(0, ns, 1, 40, { virt_text = { { ('b'):rep(10), 'Special' } }, virt_text_pos = 'inline' }) 3836 screen:expect { 3837 grid = [[ 3838 ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3839 aaaaa | 3840 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3841 aaaaa | 3842 {1:~ }| 3843 | 3844 ]], 3845 } 3846 feed('gj') 3847 screen:expect { 3848 grid = [[ 3849 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3850 ^aaaaa | 3851 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3852 aaaaa | 3853 {1:~ }| 3854 | 3855 ]], 3856 } 3857 feed('gj') 3858 screen:expect { 3859 grid = [[ 3860 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3861 aaaaa | 3862 ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3863 aaaaa | 3864 {1:~ }| 3865 | 3866 ]], 3867 } 3868 feed('gj') 3869 screen:expect { 3870 grid = [[ 3871 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3872 aaaaa | 3873 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3874 ^aaaaa | 3875 {1:~ }| 3876 | 3877 ]], 3878 } 3879 feed('gk') 3880 screen:expect { 3881 grid = [[ 3882 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3883 aaaaa | 3884 ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3885 aaaaa | 3886 {1:~ }| 3887 | 3888 ]], 3889 } 3890 feed('gk') 3891 screen:expect { 3892 grid = [[ 3893 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3894 ^aaaaa | 3895 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3896 aaaaa | 3897 {1:~ }| 3898 | 3899 ]], 3900 } 3901 feed('gk') 3902 screen:expect { 3903 grid = [[ 3904 ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3905 aaaaa | 3906 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa| 3907 aaaaa | 3908 {1:~ }| 3909 | 3910 ]], 3911 } 3912 end 3913 3914 describe('Normal mode "gj" "gk" commands work properly', function() 3915 it('with virtualedit=', function() 3916 test_normal_gj_gk() 3917 end) 3918 3919 it('with virtualedit=all', function() 3920 command('set virtualedit=all') 3921 test_normal_gj_gk() 3922 end) 3923 end) 3924 3925 it('cursor positions are correct with multiple inline virtual text', function() 3926 insert('12345678') 3927 api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' }) 3928 api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' }) 3929 feed '^' 3930 feed '4l' 3931 screen:expect { 3932 grid = [[ 3933 1234{10: virtual text virtual text }^5678 | 3934 {1:~ }| 3935 | 3936 ]], 3937 } 3938 end) 3939 3940 it('adjusts cursor location correctly when inserting around inline virtual text', function() 3941 insert('12345678') 3942 feed '$' 3943 api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' }) 3944 3945 screen:expect { 3946 grid = [[ 3947 1234{10: virtual text }567^8 | 3948 {1:~ }| 3949 | 3950 ]], 3951 } 3952 end) 3953 3954 it('has correct highlighting with multi-byte characters', function() 3955 insert('12345678') 3956 api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { 'múlti-byté chñröcters 修补', 'Special' } }, virt_text_pos = 'inline' }) 3957 3958 screen:expect { 3959 grid = [[ 3960 1234{10:múlti-byté chñröcters 修补}567^8 | 3961 {1:~ }| 3962 | 3963 ]], 3964 } 3965 end) 3966 3967 it('has correct cursor position when inserting around virtual text', function() 3968 insert('12345678') 3969 api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) 3970 feed '^' 3971 feed '3l' 3972 feed 'a' 3973 screen:expect { 3974 grid = [[ 3975 1234{10:^virtual text}5678 | 3976 {1:~ }| 3977 {8:-- INSERT --} | 3978 ]], 3979 } 3980 feed '<ESC>' 3981 screen:expect { 3982 grid = [[ 3983 123^4{10:virtual text}5678 | 3984 {1:~ }| 3985 | 3986 ]], 3987 } 3988 feed '^' 3989 feed '4l' 3990 feed 'i' 3991 screen:expect { 3992 grid = [[ 3993 1234{10:^virtual text}5678 | 3994 {1:~ }| 3995 {8:-- INSERT --} | 3996 ]], 3997 } 3998 end) 3999 4000 it('has correct cursor position with virtual text on an empty line', function() 4001 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) 4002 screen:expect { 4003 grid = [[ 4004 {10:^virtual text} | 4005 {1:~ }| 4006 | 4007 ]], 4008 } 4009 end) 4010 4011 it('text is drawn correctly with a wrapping virtual text', function() 4012 screen:try_resize(60, 8) 4013 exec([[ 4014 call setline(1, ['', 'aaa', '', 'bbbbbb']) 4015 normal gg0 4016 ]]) 4017 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('X', 60), 'Special' } }, virt_text_pos = 'inline' }) 4018 api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { string.rep('X', 61), 'Special' } }, virt_text_pos = 'inline' }) 4019 feed('$') 4020 screen:expect { 4021 grid = [[ 4022 {10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4023 aaa | 4024 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4025 {10:X} | 4026 bbbbbb | 4027 {1:~ }|*2 4028 | 4029 ]], 4030 } 4031 feed('j') 4032 screen:expect { 4033 grid = [[ 4034 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4035 aa^a | 4036 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4037 {10:X} | 4038 bbbbbb | 4039 {1:~ }|*2 4040 | 4041 ]], 4042 } 4043 feed('j') 4044 screen:expect { 4045 grid = [[ 4046 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4047 aaa | 4048 {10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4049 {10:X} | 4050 bbbbbb | 4051 {1:~ }|*2 4052 | 4053 ]], 4054 } 4055 feed('j') 4056 screen:expect { 4057 grid = [[ 4058 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4059 aaa | 4060 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4061 {10:X} | 4062 bbbbb^b | 4063 {1:~ }|*2 4064 | 4065 ]], 4066 } 4067 feed('0<C-V>2l2k') 4068 screen:expect { 4069 grid = [[ 4070 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4071 {7:aa}^a | 4072 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4073 {10:X} | 4074 {7:bbb}bbb | 4075 {1:~ }|*2 4076 {8:-- VISUAL BLOCK --} | 4077 ]], 4078 } 4079 feed([[<Esc>/aaa\n\%V<CR>]]) 4080 screen:expect { 4081 grid = [[ 4082 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4083 {12:^aaa } | 4084 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4085 {10:X} | 4086 bbbbbb | 4087 {1:~ }|*2 4088 {16:search hit BOTTOM, continuing at TOP} | 4089 ]], 4090 } 4091 feed('3ggic') 4092 screen:expect { 4093 grid = [[ 4094 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4095 {12:aaa } | 4096 c{10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4097 {10:XX} | 4098 bbbbbb | 4099 {1:~ }|*2 4100 {8:-- INSERT --} | 4101 ]], 4102 } 4103 feed([[<Esc>/aaa\nc\%V<CR>]]) 4104 screen:expect { 4105 grid = [[ 4106 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4107 {12:^aaa } | 4108 {12:c}{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4109 {10:XX} | 4110 bbbbbb | 4111 {1:~ }|*2 4112 {16:search hit BOTTOM, continuing at TOP} | 4113 ]], 4114 } 4115 end) 4116 4117 it('cursor position is correct with virtual text attached to hard TABs', function() 4118 command('set noexpandtab') 4119 feed('i') 4120 feed('<TAB>') 4121 feed('<TAB>') 4122 feed('test') 4123 feed('<ESC>') 4124 api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) 4125 feed('0') 4126 screen:expect { 4127 grid = [[ 4128 ^ {10:virtual text} test | 4129 {1:~ }| 4130 | 4131 ]], 4132 } 4133 4134 feed('l') 4135 screen:expect { 4136 grid = [[ 4137 {10:virtual text} ^ test | 4138 {1:~ }| 4139 | 4140 ]], 4141 } 4142 4143 feed('l') 4144 screen:expect { 4145 grid = [[ 4146 {10:virtual text} ^test | 4147 {1:~ }| 4148 | 4149 ]], 4150 } 4151 4152 feed('l') 4153 screen:expect { 4154 grid = [[ 4155 {10:virtual text} t^est | 4156 {1:~ }| 4157 | 4158 ]], 4159 } 4160 4161 feed('l') 4162 screen:expect { 4163 grid = [[ 4164 {10:virtual text} te^st | 4165 {1:~ }| 4166 | 4167 ]], 4168 } 4169 end) 4170 4171 it('cursor position is correct with virtual text on an empty line', function() 4172 command('set linebreak') 4173 insert('one twoword') 4174 feed('0') 4175 api.nvim_buf_set_extmark(0, ns, 0, 3, { virt_text = { { ': virtual text', 'Special' } }, virt_text_pos = 'inline' }) 4176 screen:expect { 4177 grid = [[ 4178 ^one{10:: virtual text} twoword | 4179 {1:~ }| 4180 | 4181 ]], 4182 } 4183 end) 4184 4185 it('search highlight is correct', function() 4186 insert('foo foo foo bar\nfoo foo foo bar') 4187 feed('gg0') 4188 api.nvim_buf_set_extmark(0, ns, 0, 9, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' }) 4189 api.nvim_buf_set_extmark(0, ns, 0, 9, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4190 api.nvim_buf_set_extmark(0, ns, 1, 9, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4191 api.nvim_buf_set_extmark(0, ns, 1, 9, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) 4192 screen:expect { 4193 grid = [[ 4194 ^foo foo f{10:AAABBB}oo bar | 4195 foo foo f{10:CCCDDD}oo bar | 4196 | 4197 ]], 4198 } 4199 4200 feed('/foo') 4201 screen:expect { 4202 grid = [[ 4203 {12:foo} {13:foo} {12:f}{10:AAA}{19:BBB}{12:oo} bar | 4204 {12:foo} {12:foo} {12:f}{19:CCC}{10:DDD}{12:oo} bar | 4205 /foo^ | 4206 ]], 4207 } 4208 4209 api.nvim_buf_set_extmark(0, ns, 0, 13, { virt_text = { { 'EEE', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4210 feed('<C-G>') 4211 screen:expect { 4212 grid = [[ 4213 {12:foo} {12:foo} {13:f}{10:AAA}{21:BBB}{13:oo} b{10:EEE}ar | 4214 {12:foo} {12:foo} {12:f}{19:CCC}{10:DDD}{12:oo} bar | 4215 /foo^ | 4216 ]], 4217 } 4218 end) 4219 4220 it('Visual select highlight is correct', function() 4221 insert('foo foo foo bar\nfoo foo foo bar') 4222 feed('gg0') 4223 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' }) 4224 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4225 api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4226 api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) 4227 feed('8l') 4228 screen:expect { 4229 grid = [[ 4230 foo foo {10:AAABBB}^foo bar | 4231 foo foo {10:CCCDDD}foo bar | 4232 | 4233 ]], 4234 } 4235 4236 feed('<C-V>') 4237 feed('2hj') 4238 screen:expect { 4239 grid = [[ 4240 foo fo{7:o }{10:AAA}{20:BBB}{7:f}oo bar | 4241 foo fo^o{7: }{20:CCC}{10:DDD}{7:f}oo bar | 4242 {8:-- VISUAL BLOCK --} | 4243 ]], 4244 } 4245 4246 api.nvim_buf_set_extmark(0, ns, 0, 10, { virt_text = { { 'EEE', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4247 screen:expect { 4248 grid = [[ 4249 foo fo{7:o }{10:AAA}{20:BBB}{7:f}o{10:EEE}o bar | 4250 foo fo^o{7: }{20:CCC}{10:DDD}{7:f}oo bar | 4251 {8:-- VISUAL BLOCK --} | 4252 ]], 4253 } 4254 end) 4255 4256 it('inside highlight range of another extmark', function() 4257 insert('foo foo foo bar\nfoo foo foo bar') 4258 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' }) 4259 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4260 api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4261 api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) 4262 api.nvim_buf_set_extmark(0, ns, 0, 4, { end_col = 11, hl_group = 'Search' }) 4263 api.nvim_buf_set_extmark(0, ns, 1, 4, { end_col = 11, hl_group = 'Search' }) 4264 screen:expect { 4265 grid = [[ 4266 foo {12:foo }{10:AAA}{19:BBB}{12:foo} bar | 4267 foo {12:foo }{19:CCC}{10:DDD}{12:foo} ba^r | 4268 | 4269 ]], 4270 } 4271 end) 4272 4273 it('inside highlight range of syntax', function() 4274 insert('foo foo foo bar\nfoo foo foo bar') 4275 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' }) 4276 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4277 api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 4278 api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) 4279 command([[syntax match Search 'foo \zsfoo foo\ze bar']]) 4280 screen:expect { 4281 grid = [[ 4282 foo {12:foo }{10:AAA}{19:BBB}{12:foo} bar | 4283 foo {12:foo }{19:CCC}{10:DDD}{12:foo} ba^r | 4284 | 4285 ]], 4286 } 4287 end) 4288 4289 it('cursor position is correct when inserting around a virtual text with left gravity', function() 4290 screen:try_resize(27, 4) 4291 insert(('a'):rep(15)) 4292 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { ('>'):rep(43), 'Special' } }, virt_text_pos = 'inline', right_gravity = false }) 4293 command('setlocal showbreak=+ breakindent breakindentopt=shift:2') 4294 feed('08l') 4295 screen:expect { 4296 grid = [[ 4297 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| 4298 {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| 4299 {1:+}^aaaaaaa | 4300 | 4301 ]], 4302 } 4303 feed('i') 4304 screen:expect { 4305 grid = [[ 4306 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| 4307 {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| 4308 {1:+}^aaaaaaa | 4309 {8:-- INSERT --} | 4310 ]], 4311 } 4312 feed([[<C-\><C-O>]]) 4313 screen:expect { 4314 grid = [[ 4315 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| 4316 {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| 4317 {1:+}^aaaaaaa | 4318 {8:-- (insert) --} | 4319 ]], 4320 } 4321 feed('D') 4322 screen:expect { 4323 grid = [[ 4324 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| 4325 {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| 4326 {1:^~ }| 4327 {8:-- INSERT --} | 4328 ]], 4329 } 4330 command('setlocal list listchars=eol:$') 4331 screen:expect { 4332 grid = [[ 4333 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}| 4334 {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}| 4335 {1:+^$} | 4336 {8:-- INSERT --} | 4337 ]], 4338 } 4339 feed('<C-U>') 4340 screen:expect { 4341 grid = [[ 4342 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4343 {1:+}{10:>>>>>>>>>>>>>>>>}{1:^$} | 4344 {1:~ }| 4345 {8:-- INSERT --} | 4346 ]], 4347 } 4348 feed('a') 4349 screen:expect { 4350 grid = [[ 4351 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4352 {1:+}{10:>>>>>>>>>>>>>>>>}a{1:^$} | 4353 {1:~ }| 4354 {8:-- INSERT --} | 4355 ]], 4356 } 4357 feed('<Esc>') 4358 screen:expect { 4359 grid = [[ 4360 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4361 {1:+}{10:>>>>>>>>>>>>>>>>}^a{1:$} | 4362 {1:~ }| 4363 | 4364 ]], 4365 } 4366 feed('x') 4367 screen:expect { 4368 grid = [[ 4369 {10:^>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4370 {1:+}{10:>>>>>>>>>>>>>>>>}{1:$} | 4371 {1:~ }| 4372 | 4373 ]], 4374 } 4375 end) 4376 4377 it('cursor position is correct when inserting around virtual texts with both left and right gravity', function() 4378 screen:try_resize(30, 4) 4379 command('setlocal showbreak=+ breakindent breakindentopt=shift:2') 4380 insert(('a'):rep(15)) 4381 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { ('>'):rep(32), 'Special' } }, virt_text_pos = 'inline', right_gravity = false }) 4382 api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { ('<'):rep(32), 'Special' } }, virt_text_pos = 'inline', right_gravity = true }) 4383 feed('08l') 4384 screen:expect { 4385 grid = [[ 4386 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| 4387 {1:+}{10:>>>>>>>>>><<<<<<<<<<<<<<<<<}| 4388 {1:+}{10:<<<<<<<<<<<<<<<}^aaaaaaa | 4389 | 4390 ]], 4391 } 4392 feed('i') 4393 screen:expect { 4394 grid = [[ 4395 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| 4396 {1:+}{10:>>>>>>>>>>^<<<<<<<<<<<<<<<<<}| 4397 {1:+}{10:<<<<<<<<<<<<<<<}aaaaaaa | 4398 {8:-- INSERT --} | 4399 ]], 4400 } 4401 feed('a') 4402 screen:expect { 4403 grid = [[ 4404 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| 4405 {1:+}{10:>>>>>>>>>>}a{10:^<<<<<<<<<<<<<<<<}| 4406 {1:+}{10:<<<<<<<<<<<<<<<<}aaaaaaa | 4407 {8:-- INSERT --} | 4408 ]], 4409 } 4410 feed([[<C-\><C-O>]]) 4411 screen:expect { 4412 grid = [[ 4413 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| 4414 {1:+}{10:>>>>>>>>>>}a{10:<<<<<<<<<<<<<<<<}| 4415 {1:+}{10:<<<<<<<<<<<<<<<<}^aaaaaaa | 4416 {8:-- (insert) --} | 4417 ]], 4418 } 4419 feed('D') 4420 screen:expect { 4421 grid = [[ 4422 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| 4423 {1:+}{10:>>>>>>>>>>}a{10:^<<<<<<<<<<<<<<<<}| 4424 {1:+}{10:<<<<<<<<<<<<<<<<} | 4425 {8:-- INSERT --} | 4426 ]], 4427 } 4428 feed('<BS>') 4429 screen:expect { 4430 grid = [[ 4431 aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}| 4432 {1:+}{10:>>>>>>>>>>^<<<<<<<<<<<<<<<<<}| 4433 {1:+}{10:<<<<<<<<<<<<<<<} | 4434 {8:-- INSERT --} | 4435 ]], 4436 } 4437 feed('<C-U>') 4438 screen:expect { 4439 grid = [[ 4440 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4441 {1:+}{10:>>^<<<<<<<<<<<<<<<<<<<<<<<<<}| 4442 {1:+}{10:<<<<<<<} | 4443 {8:-- INSERT --} | 4444 ]], 4445 } 4446 feed('a') 4447 screen:expect { 4448 grid = [[ 4449 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4450 {1:+}{10:>>}a{10:^<<<<<<<<<<<<<<<<<<<<<<<<}| 4451 {1:+}{10:<<<<<<<<} | 4452 {8:-- INSERT --} | 4453 ]], 4454 } 4455 feed('<Esc>') 4456 screen:expect { 4457 grid = [[ 4458 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4459 {1:+}{10:>>}^a{10:<<<<<<<<<<<<<<<<<<<<<<<<}| 4460 {1:+}{10:<<<<<<<<} | 4461 | 4462 ]], 4463 } 4464 feed('x') 4465 screen:expect { 4466 grid = [[ 4467 {10:^>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4468 {1:+}{10:>><<<<<<<<<<<<<<<<<<<<<<<<<}| 4469 {1:+}{10:<<<<<<<} | 4470 | 4471 ]], 4472 } 4473 feed('i') 4474 screen:expect { 4475 grid = [[ 4476 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4477 {1:+}{10:>>^<<<<<<<<<<<<<<<<<<<<<<<<<}| 4478 {1:+}{10:<<<<<<<} | 4479 {8:-- INSERT --} | 4480 ]], 4481 } 4482 screen:try_resize(32, 4) 4483 screen:expect { 4484 grid = [[ 4485 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4486 {1:+}{10:^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<}| 4487 {1:+}{10:<<<} | 4488 {8:-- INSERT --} | 4489 ]], 4490 } 4491 command('setlocal nobreakindent') 4492 screen:expect { 4493 grid = [[ 4494 {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}| 4495 {1:+}{10:^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<}| 4496 {1:+}{10:<} | 4497 {8:-- INSERT --} | 4498 ]], 4499 } 4500 end) 4501 4502 it('draws correctly with no wrap multiple virtual text, where one is hidden', function() 4503 insert('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz') 4504 command('set nowrap') 4505 api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) 4506 api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) 4507 feed('$') 4508 screen:expect { 4509 grid = [[ 4510 opqrstuvwxyzabcdefghijklmnopqrstuvwx{10:virtual text}y^z| 4511 {1:~ }| 4512 | 4513 ]], 4514 } 4515 end) 4516 4517 it('draws correctly with no wrap and a long virtual text', function() 4518 insert('abcdefghi') 4519 command('set nowrap') 4520 api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' }) 4521 feed('$') 4522 screen:expect([[ 4523 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i| 4524 {1:~ }| 4525 | 4526 ]]) 4527 command('set list listchars+=precedes:!') 4528 screen:expect([[ 4529 {1:!}{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i| 4530 {1:~ }| 4531 | 4532 ]]) 4533 end) 4534 4535 it('draws correctly with no wrap and multibyte virtual text', function() 4536 insert('12345678') 4537 command('set nowrap') 4538 api.nvim_buf_set_extmark(0, ns, 0, 2, { 4539 hl_mode = 'replace', 4540 virt_text = { { 'α口β̳γ̲=', 'Special' }, { '❤️', 'Special' } }, 4541 virt_text_pos = 'inline', 4542 }) 4543 screen:expect([[ 4544 12{10:α口β̳γ̲=❤️}34567^8 | 4545 {1:~ }| 4546 | 4547 ]]) 4548 feed('zl') 4549 screen:expect([[ 4550 2{10:α口β̳γ̲=❤️}34567^8 | 4551 {1:~ }| 4552 | 4553 ]]) 4554 feed('zl') 4555 screen:expect([[ 4556 {10:α口β̳γ̲=❤️}34567^8 | 4557 {1:~ }| 4558 | 4559 ]]) 4560 feed('zl') 4561 screen:expect([[ 4562 {10:口β̳γ̲=❤️}34567^8 | 4563 {1:~ }| 4564 | 4565 ]]) 4566 feed('V') 4567 screen:expect([[ 4568 {10:口β̳γ̲=❤️}{7:34567}^8 | 4569 {1:~ }| 4570 {8:-- VISUAL LINE --} | 4571 ]]) 4572 command('set list listchars+=precedes:!') 4573 screen:expect([[ 4574 {1:!<}{10:β̳γ̲=❤️}{7:34567}^8 | 4575 {1:~ }| 4576 {8:-- VISUAL LINE --} | 4577 ]]) 4578 feed('zl') 4579 screen:expect([[ 4580 {1:!}{10:β̳γ̲=❤️}{7:34567}^8 | 4581 {1:~ }| 4582 {8:-- VISUAL LINE --} | 4583 ]]) 4584 command('set nolist') 4585 screen:expect([[ 4586 {1:<}{10:β̳γ̲=❤️}{7:34567}^8 | 4587 {1:~ }| 4588 {8:-- VISUAL LINE --} | 4589 ]]) 4590 feed('<Esc>') 4591 screen:expect([[ 4592 {1:<}{10:β̳γ̲=❤️}34567^8 | 4593 {1:~ }| 4594 | 4595 ]]) 4596 feed('zl') 4597 screen:expect([[ 4598 {10:β̳γ̲=❤️}34567^8 | 4599 {1:~ }| 4600 | 4601 ]]) 4602 feed('zl') 4603 screen:expect([[ 4604 {10:γ̲=❤️}34567^8 | 4605 {1:~ }| 4606 | 4607 ]]) 4608 feed('zl') 4609 screen:expect([[ 4610 {10:=❤️}34567^8 | 4611 {1:~ }| 4612 | 4613 ]]) 4614 feed('zl') 4615 screen:expect([[ 4616 {10:❤️}34567^8 | 4617 {1:~ }| 4618 | 4619 ]]) 4620 command('set list') 4621 screen:expect([[ 4622 {1:!<}34567^8 | 4623 {1:~ }| 4624 | 4625 ]]) 4626 feed('zl') 4627 screen:expect([[ 4628 {1:!}34567^8 | 4629 {1:~ }| 4630 | 4631 ]]) 4632 command('set nolist') 4633 screen:expect([[ 4634 {1:<}34567^8 | 4635 {1:~ }| 4636 | 4637 ]]) 4638 feed('zl') 4639 screen:expect([[ 4640 34567^8 | 4641 {1:~ }| 4642 | 4643 ]]) 4644 feed('zl') 4645 screen:expect([[ 4646 4567^8 | 4647 {1:~ }| 4648 | 4649 ]]) 4650 end) 4651 4652 it('tabs are the correct length with no wrap following virtual text', function() 4653 command('set nowrap') 4654 feed('itest<TAB>a<ESC>') 4655 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' }) 4656 feed('gg$') 4657 screen:expect { 4658 grid = [[ 4659 {10:aaaaaaaaaaaaaaaaaaaaaaaaa}test ^a | 4660 {1:~ }| 4661 | 4662 ]], 4663 } 4664 end) 4665 4666 it('highlighting does not extend with no wrap and a long virtual text', function() 4667 insert('abcdef') 4668 command('set nowrap') 4669 api.nvim_buf_set_extmark(0, ns, 0, 3, { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline' }) 4670 feed('$') 4671 screen:expect { 4672 grid = [[ 4673 {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}de^f| 4674 {1:~ }| 4675 | 4676 ]], 4677 } 4678 end) 4679 4680 it('hidden virtual text does not interfere with Visual highlight', function() 4681 insert('abcdef') 4682 command('set nowrap') 4683 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'XXX', 'Special' } }, virt_text_pos = 'inline' }) 4684 feed('V2zl') 4685 screen:expect { 4686 grid = [[ 4687 {10:X}{7:abcde}^f | 4688 {1:~ }| 4689 {8:-- VISUAL LINE --} | 4690 ]], 4691 } 4692 feed('zl') 4693 screen:expect { 4694 grid = [[ 4695 {7:abcde}^f | 4696 {1:~ }| 4697 {8:-- VISUAL LINE --} | 4698 ]], 4699 } 4700 feed('zl') 4701 screen:expect { 4702 grid = [[ 4703 {7:bcde}^f | 4704 {1:~ }| 4705 {8:-- VISUAL LINE --} | 4706 ]], 4707 } 4708 end) 4709 4710 it('highlighting is correct when virtual text wraps with number', function() 4711 screen:try_resize(50, 5) 4712 insert([[ 4713 test 4714 test]]) 4715 command('set number') 4716 api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' }) 4717 feed('gg0') 4718 screen:expect { 4719 grid = [[ 4720 {2: 1 }^t{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4721 {2: }{10:XXXXXXXXXX}est | 4722 {2: 2 }test | 4723 {1:~ }| 4724 | 4725 ]], 4726 } 4727 end) 4728 4729 it('highlighting is correct when virtual text is proceeded with a match', function() 4730 insert([[test]]) 4731 api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) 4732 feed('gg0') 4733 command('match ErrorMsg /e/') 4734 screen:expect { 4735 grid = [[ 4736 ^t{4:e}{10:virtual text}st | 4737 {1:~ }| 4738 | 4739 ]], 4740 } 4741 command('match ErrorMsg /s/') 4742 screen:expect { 4743 grid = [[ 4744 ^te{10:virtual text}{4:s}t | 4745 {1:~ }| 4746 | 4747 ]], 4748 } 4749 end) 4750 4751 it('smoothscroll works correctly when virtual text wraps', function() 4752 insert('foobar') 4753 api.nvim_buf_set_extmark(0, ns, 0, 3, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' }) 4754 command('setlocal smoothscroll') 4755 screen:expect { 4756 grid = [[ 4757 foo{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| 4758 {10:XXXXXXXX}ba^r | 4759 | 4760 ]], 4761 } 4762 feed('<C-E>') 4763 screen:expect { 4764 grid = [[ 4765 {1:<<<}{10:XXXXX}ba^r | 4766 {1:~ }| 4767 | 4768 ]], 4769 } 4770 end) 4771 4772 it('in diff mode is highlighted correct', function() 4773 screen:try_resize(50, 10) 4774 insert([[ 4775 9000 4776 0009 4777 0009 4778 9000 4779 0009 4780 ]]) 4781 insert('aaa\tbbb') 4782 command('set diff') 4783 api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline', right_gravity = false }) 4784 api.nvim_buf_set_extmark(0, ns, 5, 0, { virt_text = { { '!', 'Special' } }, virt_text_pos = 'inline' }) 4785 api.nvim_buf_set_extmark(0, ns, 5, 3, { virt_text = { { '' } }, virt_text_pos = 'inline' }) 4786 command('vnew') 4787 insert([[ 4788 000 4789 000 4790 000 4791 000 4792 000 4793 ]]) 4794 insert('aaabbb') 4795 command('set diff') 4796 feed('gg0') 4797 screen:expect { 4798 grid = [[ 4799 {9:^000 }│{5:9}{14:test}{9:000 }| 4800 {9:000 }│{9:000}{5:9}{9: }|*2 4801 {9:000 }│{5:9}{9:000 }| 4802 {9:000 }│{9:000}{5:9}{9: }| 4803 {9:aaabbb }│{14:!}{9:aaa}{5: }{9:bbb }| 4804 {1:~ }│{1:~ }|*2 4805 {15:[No Name] [+] }{13:[No Name] [+] }| 4806 | 4807 ]], 4808 } 4809 command('wincmd w | set nowrap') 4810 feed('zl') 4811 screen:expect { 4812 grid = [[ 4813 {9:000 }│{14:test}{9:000 }| 4814 {9:000 }│{9:00}{5:9}{9: }|*2 4815 {9:000 }│{9:000 }| 4816 {9:000 }│{9:00}{5:9}{9: }| 4817 {9:aaabbb }│{9:aaa}{5: }{9:bb^b }| 4818 {1:~ }│{1:~ }|*2 4819 {13:[No Name] [+] }{15:[No Name] [+] }| 4820 | 4821 ]], 4822 } 4823 end) 4824 4825 it('correctly draws when there are multiple overlapping virtual texts on the same line with nowrap', function() 4826 command('set nowrap') 4827 insert('a') 4828 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' }) 4829 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('b', 55), 'Special' } }, virt_text_pos = 'inline' }) 4830 feed('$') 4831 screen:expect { 4832 grid = [[ 4833 {10:bbbbbbbbbbbbbbbbbbbbbbbbb}^a | 4834 {1:~ }| 4835 | 4836 ]], 4837 } 4838 end) 4839 4840 it('correctly draws when overflowing virtual text is followed by TAB with no wrap', function() 4841 command('set nowrap') 4842 feed('i<TAB>test<ESC>') 4843 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 60), 'Special' } }, virt_text_pos = 'inline' }) 4844 feed('0') 4845 screen:expect({ 4846 grid = [[ 4847 {10:aaaaaaaaaaaaaaaaaaaaaa} ^ test | 4848 {1:~ }| 4849 | 4850 ]], 4851 }) 4852 end) 4853 4854 it('does not crash at column 0 when folded in a wide window', function() 4855 screen:try_resize(82, 5) 4856 command('hi! CursorLine guibg=NONE guifg=Red gui=NONE') 4857 command('set cursorline') 4858 insert([[ 4859 aaaaa 4860 bbbbb 4861 4862 ccccc]]) 4863 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' }) 4864 api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'bar' } }, virt_text_pos = 'inline' }) 4865 screen:expect { 4866 grid = [[ 4867 fooaaaaa | 4868 bbbbb | 4869 bar | 4870 {16:cccc^c }| 4871 | 4872 ]], 4873 } 4874 command('1,2fold') 4875 screen:expect { 4876 grid = [[ 4877 {17:+-- 2 lines: aaaaa·······························································}| 4878 bar | 4879 {16:cccc^c }| 4880 {1:~ }| 4881 | 4882 ]], 4883 } 4884 feed('2k') 4885 screen:expect { 4886 grid = [[ 4887 {18:^+-- 2 lines: aaaaa·······························································}| 4888 bar | 4889 ccccc | 4890 {1:~ }| 4891 | 4892 ]], 4893 } 4894 command('3,4fold') 4895 screen:expect { 4896 grid = [[ 4897 {18:^+-- 2 lines: aaaaa·······························································}| 4898 {17:+-- 2 lines: ccccc·······························································}| 4899 {1:~ }|*2 4900 | 4901 ]], 4902 } 4903 feed('j') 4904 screen:expect { 4905 grid = [[ 4906 {17:+-- 2 lines: aaaaa·······························································}| 4907 {18:^+-- 2 lines: ccccc·······························································}| 4908 {1:~ }|*2 4909 | 4910 ]], 4911 } 4912 end) 4913 4914 it('does not crash at right edge of wide window #23848', function() 4915 screen:try_resize(82, 5) 4916 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { ('a'):rep(82) }, { 'b' } }, virt_text_pos = 'inline' }) 4917 screen:expect { 4918 grid = [[ 4919 ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 4920 b | 4921 {1:~ }|*2 4922 | 4923 ]], 4924 } 4925 command('set nowrap') 4926 screen:expect { 4927 grid = [[ 4928 ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 4929 {1:~ }|*3 4930 | 4931 ]], 4932 } 4933 feed('82i0<Esc>0') 4934 screen:expect { 4935 grid = [[ 4936 ^0000000000000000000000000000000000000000000000000000000000000000000000000000000000| 4937 {1:~ }|*3 4938 | 4939 ]], 4940 } 4941 command('set wrap') 4942 screen:expect { 4943 grid = [[ 4944 ^0000000000000000000000000000000000000000000000000000000000000000000000000000000000| 4945 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 4946 b | 4947 {1:~ }| 4948 | 4949 ]], 4950 } 4951 end) 4952 4953 it('lcs-extends is drawn with inline virtual text at end of screen line', function() 4954 exec([[ 4955 setlocal nowrap list listchars=extends:! 4956 call setline(1, repeat('a', 51)) 4957 ]]) 4958 api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' }) 4959 feed('20l') 4960 screen:expect { 4961 grid = [[ 4962 aaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:!}| 4963 {1:~ }| 4964 | 4965 ]], 4966 } 4967 feed('zl') 4968 screen:expect { 4969 grid = [[ 4970 aaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:!}| 4971 {1:~ }| 4972 | 4973 ]], 4974 } 4975 feed('zl') 4976 screen:expect { 4977 grid = [[ 4978 aaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:b}{1:!}| 4979 {1:~ }| 4980 | 4981 ]], 4982 } 4983 feed('zl') 4984 screen:expect { 4985 grid = [[ 4986 aaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bb}{1:!}| 4987 {1:~ }| 4988 | 4989 ]], 4990 } 4991 feed('zl') 4992 screen:expect { 4993 grid = [[ 4994 aaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbb}a| 4995 {1:~ }| 4996 | 4997 ]], 4998 } 4999 end) 5000 5001 it('lcs-extends is drawn with only inline virtual text offscreen', function() 5002 command('set nowrap') 5003 command('set list') 5004 command('set listchars+=extends:c') 5005 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline' }) 5006 insert(string.rep('a', 50)) 5007 feed('gg0') 5008 screen:expect { 5009 grid = [[ 5010 ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:c}| 5011 {1:~ }| 5012 | 5013 ]], 5014 } 5015 end) 5016 5017 it('blockwise Visual highlight with double-width virtual text (replace)', function() 5018 screen:try_resize(60, 6) 5019 insert('123456789\n123456789\n123456789\n123456789') 5020 api.nvim_buf_set_extmark(0, ns, 1, 1, { virt_text = { { '-口-', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) 5021 api.nvim_buf_set_extmark(0, ns, 2, 2, { virt_text = { { '口', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' }) 5022 feed('gg0') 5023 screen:expect { 5024 grid = [[ 5025 ^123456789 | 5026 1{10:-口-}23456789 | 5027 12{10:口}3456789 | 5028 123456789 | 5029 {1:~ }| 5030 | 5031 ]], 5032 } 5033 feed('<C-V>3jl') 5034 screen:expect { 5035 grid = [[ 5036 {7:12}3456789 | 5037 {7:1}{10:-口-}23456789 | 5038 {7:12}{10:口}3456789 | 5039 {7:1}^23456789 | 5040 {1:~ }| 5041 {8:-- VISUAL BLOCK --} | 5042 ]], 5043 } 5044 feed('l') 5045 screen:expect { 5046 grid = [[ 5047 {7:123}456789 | 5048 {7:1}{10:-口-}23456789 | 5049 {7:12}{10:口}3456789 | 5050 {7:12}^3456789 | 5051 {1:~ }| 5052 {8:-- VISUAL BLOCK --} | 5053 ]], 5054 } 5055 feed('4l') 5056 screen:expect { 5057 grid = [[ 5058 {7:1234567}89 | 5059 {7:1}{10:-口-}{7:23}456789 | 5060 {7:12}{10:口}{7:345}6789 | 5061 {7:123456}^789 | 5062 {1:~ }| 5063 {8:-- VISUAL BLOCK --} | 5064 ]], 5065 } 5066 feed('Ol') 5067 screen:expect { 5068 grid = [[ 5069 1{7:234567}89 | 5070 1{10:-口-}{7:23}456789 | 5071 1{7:2}{10:口}{7:345}6789 | 5072 1^2{7:34567}89 | 5073 {1:~ }| 5074 {8:-- VISUAL BLOCK --} | 5075 ]], 5076 } 5077 feed('l') 5078 screen:expect { 5079 grid = [[ 5080 12{7:34567}89 | 5081 1{10:-口-}{7:23}456789 | 5082 12{10:口}{7:345}6789 | 5083 12^3{7:4567}89 | 5084 {1:~ }| 5085 {8:-- VISUAL BLOCK --} | 5086 ]], 5087 } 5088 feed('l') 5089 screen:expect { 5090 grid = [[ 5091 123{7:4567}89 | 5092 1{10:-口-}{7:23}456789 | 5093 12{10:口}{7:345}6789 | 5094 123^4{7:567}89 | 5095 {1:~ }| 5096 {8:-- VISUAL BLOCK --} | 5097 ]], 5098 } 5099 end) 5100 5101 it('blockwise Visual highlight with double-width virtual text (combine)', function() 5102 screen:try_resize(60, 6) 5103 insert('123456789\n123456789\n123456789\n123456789') 5104 api.nvim_buf_set_extmark(0, ns, 1, 1, { virt_text = { { '-口-', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 5105 api.nvim_buf_set_extmark(0, ns, 2, 2, { virt_text = { { '口', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' }) 5106 feed('gg0') 5107 screen:expect { 5108 grid = [[ 5109 ^123456789 | 5110 1{10:-口-}23456789 | 5111 12{10:口}3456789 | 5112 123456789 | 5113 {1:~ }| 5114 | 5115 ]], 5116 } 5117 feed('<C-V>3jl') 5118 screen:expect { 5119 grid = [[ 5120 {7:12}3456789 | 5121 {7:1}{20:-}{10:口-}23456789 | 5122 {7:12}{10:口}3456789 | 5123 {7:1}^23456789 | 5124 {1:~ }| 5125 {8:-- VISUAL BLOCK --} | 5126 ]], 5127 } 5128 feed('l') 5129 screen:expect { 5130 grid = [[ 5131 {7:123}456789 | 5132 {7:1}{20:-口}{10:-}23456789 | 5133 {7:12}{20:口}3456789 | 5134 {7:12}^3456789 | 5135 {1:~ }| 5136 {8:-- VISUAL BLOCK --} | 5137 ]], 5138 } 5139 feed('4l') 5140 screen:expect { 5141 grid = [[ 5142 {7:1234567}89 | 5143 {7:1}{20:-口-}{7:23}456789 | 5144 {7:12}{20:口}{7:345}6789 | 5145 {7:123456}^789 | 5146 {1:~ }| 5147 {8:-- VISUAL BLOCK --} | 5148 ]], 5149 } 5150 feed('Ol') 5151 screen:expect { 5152 grid = [[ 5153 1{7:234567}89 | 5154 1{20:-口-}{7:23}456789 | 5155 1{7:2}{20:口}{7:345}6789 | 5156 1^2{7:34567}89 | 5157 {1:~ }| 5158 {8:-- VISUAL BLOCK --} | 5159 ]], 5160 } 5161 feed('l') 5162 screen:expect { 5163 grid = [[ 5164 12{7:34567}89 | 5165 1{10:-}{20:口-}{7:23}456789 | 5166 12{20:口}{7:345}6789 | 5167 12^3{7:4567}89 | 5168 {1:~ }| 5169 {8:-- VISUAL BLOCK --} | 5170 ]], 5171 } 5172 feed('l') 5173 screen:expect { 5174 grid = [[ 5175 123{7:4567}89 | 5176 1{10:-}{20:口-}{7:23}456789 | 5177 12{20:口}{7:345}6789 | 5178 123^4{7:567}89 | 5179 {1:~ }| 5180 {8:-- VISUAL BLOCK --} | 5181 ]], 5182 } 5183 end) 5184 5185 local function test_virt_inline_showbreak_smoothscroll() 5186 screen:try_resize(30, 6) 5187 exec([[ 5188 highlight! link LineNr Normal 5189 setlocal number showbreak=+ breakindent breakindentopt=shift:2 5190 setlocal scrolloff=0 smoothscroll 5191 call setline(1, repeat('a', 28)) 5192 normal! $ 5193 ]]) 5194 api.nvim_buf_set_extmark(0, ns, 0, 27, { virt_text = { { ('123'):rep(23) } }, virt_text_pos = 'inline' }) 5195 feed(':<CR>') -- Have a screen line that doesn't start with spaces 5196 screen:expect { 5197 grid = [[ 5198 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| 5199 {1:+}a1231231231231231231231| 5200 {1:+}23123123123123123123123| 5201 {1:+}12312312312312312312312| 5202 {1:+}3^a | 5203 : | 5204 ]], 5205 } 5206 feed('<C-E>') 5207 screen:expect { 5208 grid = [[ 5209 {1:+}a1231231231231231231231| 5210 {1:+}23123123123123123123123| 5211 {1:+}12312312312312312312312| 5212 {1:+}3^a | 5213 {1:~ }| 5214 : | 5215 ]], 5216 } 5217 feed('<C-E>') 5218 screen:expect { 5219 grid = [[ 5220 {1:+}23123123123123123123123| 5221 {1:+}12312312312312312312312| 5222 {1:+}3^a | 5223 {1:~ }|*2 5224 : | 5225 ]], 5226 } 5227 feed('<C-E>') 5228 screen:expect { 5229 grid = [[ 5230 {1:+}12312312312312312312312| 5231 {1:+}3^a | 5232 {1:~ }|*3 5233 : | 5234 ]], 5235 } 5236 feed('<C-E>') 5237 screen:expect { 5238 grid = [[ 5239 {1:+}3^a | 5240 {1:~ }|*4 5241 : | 5242 ]], 5243 } 5244 feed('zbi') 5245 screen:expect { 5246 grid = [[ 5247 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| 5248 {1:+}a^1231231231231231231231| 5249 {1:+}23123123123123123123123| 5250 {1:+}12312312312312312312312| 5251 {1:+}3a | 5252 {8:-- INSERT --} | 5253 ]], 5254 } 5255 feed('<BS>') 5256 screen:expect { 5257 grid = [[ 5258 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| 5259 {1:+}^12312312312312312312312| 5260 {1:+}31231231231231231231231| 5261 {1:+}23123123123123123123123| 5262 {1:+}a | 5263 {8:-- INSERT --} | 5264 ]], 5265 } 5266 feed('<Esc>l') 5267 feed(':<CR>') -- Have a screen line that doesn't start with spaces 5268 screen:expect { 5269 grid = [[ 5270 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| 5271 {1:+}12312312312312312312312| 5272 {1:+}31231231231231231231231| 5273 {1:+}23123123123123123123123| 5274 {1:+}^a | 5275 : | 5276 ]], 5277 } 5278 feed('<C-E>') 5279 screen:expect { 5280 grid = [[ 5281 {1:+}12312312312312312312312| 5282 {1:+}31231231231231231231231| 5283 {1:+}23123123123123123123123| 5284 {1:+}^a | 5285 {1:~ }| 5286 : | 5287 ]], 5288 } 5289 feed('<C-E>') 5290 screen:expect { 5291 grid = [[ 5292 {1:+}31231231231231231231231| 5293 {1:+}23123123123123123123123| 5294 {1:+}^a | 5295 {1:~ }|*2 5296 : | 5297 ]], 5298 } 5299 feed('<C-E>') 5300 screen:expect { 5301 grid = [[ 5302 {1:+}23123123123123123123123| 5303 {1:+}^a | 5304 {1:~ }|*3 5305 : | 5306 ]], 5307 } 5308 feed('<C-E>') 5309 screen:expect { 5310 grid = [[ 5311 {1:+}^a | 5312 {1:~ }|*4 5313 : | 5314 ]], 5315 } 5316 feed('023x$') 5317 screen:expect { 5318 grid = [[ 5319 1 aaa12312312312312312312312| 5320 {1:+}31231231231231231231231| 5321 {1:+}23123123123123123123123| 5322 {1:+}^a | 5323 {1:~ }| 5324 : | 5325 ]], 5326 } 5327 feed('<C-E>') 5328 screen:expect { 5329 grid = [[ 5330 {1:+}31231231231231231231231| 5331 {1:+}23123123123123123123123| 5332 {1:+}^a | 5333 {1:~ }|*2 5334 : | 5335 ]], 5336 } 5337 feed('<C-E>') 5338 screen:expect { 5339 grid = [[ 5340 {1:+}23123123123123123123123| 5341 {1:+}^a | 5342 {1:~ }|*3 5343 : | 5344 ]], 5345 } 5346 feed('<C-E>') 5347 screen:expect { 5348 grid = [[ 5349 {1:+}^a | 5350 {1:~ }|*4 5351 : | 5352 ]], 5353 } 5354 feed('zbi') 5355 screen:expect { 5356 grid = [[ 5357 1 aaa^12312312312312312312312| 5358 {1:+}31231231231231231231231| 5359 {1:+}23123123123123123123123| 5360 {1:+}a | 5361 {1:~ }| 5362 {8:-- INSERT --} | 5363 ]], 5364 } 5365 feed('<C-U>') 5366 screen:expect { 5367 grid = [[ 5368 1 ^12312312312312312312312312| 5369 {1:+}31231231231231231231231| 5370 {1:+}23123123123123123123a | 5371 {1:~ }|*2 5372 {8:-- INSERT --} | 5373 ]], 5374 } 5375 feed('<Esc>') 5376 screen:expect { 5377 grid = [[ 5378 1 12312312312312312312312312| 5379 {1:+}31231231231231231231231| 5380 {1:+}23123123123123123123^a | 5381 {1:~ }|*2 5382 | 5383 ]], 5384 } 5385 feed('<C-E>') 5386 screen:expect { 5387 grid = [[ 5388 {1:+}31231231231231231231231| 5389 {1:+}23123123123123123123^a | 5390 {1:~ }|*3 5391 | 5392 ]], 5393 } 5394 feed('<C-E>') 5395 screen:expect { 5396 grid = [[ 5397 {1:+}23123123123123123123^a | 5398 {1:~ }|*4 5399 | 5400 ]], 5401 } 5402 feed('zbx') 5403 screen:expect { 5404 grid = [[ 5405 1 ^12312312312312312312312312| 5406 {1:+}31231231231231231231231| 5407 {1:+}23123123123123123123 | 5408 {1:~ }|*2 5409 | 5410 ]], 5411 } 5412 feed('26ia<Esc>a') 5413 screen:expect { 5414 grid = [[ 5415 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| 5416 {1:+}^12312312312312312312312| 5417 {1:+}31231231231231231231231| 5418 {1:+}23123123123123123123123| 5419 {1:~ }| 5420 {8:-- INSERT --} | 5421 ]], 5422 } 5423 feed([[<C-\><C-O>:setlocal breakindentopt=<CR>]]) 5424 screen:expect { 5425 grid = [[ 5426 1 aaaaaaaaaaaaaaaaaaaaaaaaaa| 5427 {1:+}^1231231231231231231231231| 5428 {1:+}2312312312312312312312312| 5429 {1:+}3123123123123123123 | 5430 {1:~ }| 5431 {8:-- INSERT --} | 5432 ]], 5433 } 5434 end 5435 5436 describe('with showbreak, smoothscroll', function() 5437 it('and cpoptions-=n', function() 5438 test_virt_inline_showbreak_smoothscroll() 5439 end) 5440 5441 it('and cpoptions+=n', function() 5442 command('set cpoptions+=n') 5443 -- because of 'breakindent' the screen states are the same 5444 test_virt_inline_showbreak_smoothscroll() 5445 end) 5446 end) 5447 5448 it('before TABs with smoothscroll', function() 5449 screen:try_resize(30, 6) 5450 exec([[ 5451 setlocal list listchars=tab:<-> scrolloff=0 smoothscroll 5452 call setline(1, repeat("\t", 4) .. 'a') 5453 normal! $ 5454 ]]) 5455 api.nvim_buf_set_extmark(0, ns, 0, 3, { virt_text = { { ('12'):rep(32) } }, virt_text_pos = 'inline' }) 5456 screen:expect { 5457 grid = [[ 5458 {1:<------><------><------>}121212| 5459 121212121212121212121212121212| 5460 1212121212121212121212121212{1:<-}| 5461 {1:----->}^a | 5462 {1:~ }| 5463 | 5464 ]], 5465 } 5466 feed('<C-E>') 5467 screen:expect { 5468 grid = [[ 5469 {1:<<<}212121212121212121212121212| 5470 1212121212121212121212121212{1:<-}| 5471 {1:----->}^a | 5472 {1:~ }|*2 5473 | 5474 ]], 5475 } 5476 feed('<C-E>') 5477 screen:expect { 5478 grid = [[ 5479 {1:<<<}2121212121212121212121212{1:<-}| 5480 {1:----->}^a | 5481 {1:~ }|*3 5482 | 5483 ]], 5484 } 5485 feed('<C-E>') 5486 screen:expect { 5487 grid = [[ 5488 {1:<<<-->}^a | 5489 {1:~ }|*4 5490 | 5491 ]], 5492 } 5493 feed('zbh') 5494 screen:expect { 5495 grid = [[ 5496 {1:<------><------><------>}121212| 5497 121212121212121212121212121212| 5498 1212121212121212121212121212{1:^<-}| 5499 {1:----->}a | 5500 {1:~ }| 5501 | 5502 ]], 5503 } 5504 feed('i') 5505 screen:expect { 5506 grid = [[ 5507 {1:<------><------><------>}^121212| 5508 121212121212121212121212121212| 5509 1212121212121212121212121212{1:<-}| 5510 {1:----->}a | 5511 {1:~ }| 5512 {8:-- INSERT --} | 5513 ]], 5514 } 5515 feed('<C-O>:setlocal nolist<CR>') 5516 screen:expect { 5517 grid = [[ 5518 ^121212| 5519 121212121212121212121212121212| 5520 1212121212121212121212121212 | 5521 a | 5522 {1:~ }| 5523 {8:-- INSERT --} | 5524 ]], 5525 } 5526 feed('<Esc>l') 5527 screen:expect { 5528 grid = [[ 5529 121212| 5530 121212121212121212121212121212| 5531 1212121212121212121212121212 | 5532 ^ a | 5533 {1:~ }| 5534 | 5535 ]], 5536 } 5537 feed('<C-E>') 5538 screen:expect { 5539 grid = [[ 5540 {1:<<<}212121212121212121212121212| 5541 1212121212121212121212121212 | 5542 ^ a | 5543 {1:~ }|*2 5544 | 5545 ]], 5546 } 5547 feed('<C-E>') 5548 screen:expect { 5549 grid = [[ 5550 {1:<<<}2121212121212121212121212 | 5551 ^ a | 5552 {1:~ }|*3 5553 | 5554 ]], 5555 } 5556 feed('<C-E>') 5557 screen:expect { 5558 grid = [[ 5559 {1:<<<} ^ a | 5560 {1:~ }|*4 5561 | 5562 ]], 5563 } 5564 end) 5565 5566 it('before a space with linebreak', function() 5567 screen:try_resize(50, 6) 5568 exec([[ 5569 setlocal linebreak showbreak=+ breakindent breakindentopt=shift:2 5570 call setline(1, repeat('a', 50) .. ' ' .. repeat('c', 45)) 5571 normal! $ 5572 ]]) 5573 api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { ('b'):rep(10) } }, virt_text_pos = 'inline' }) 5574 screen:expect { 5575 grid = [[ 5576 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 5577 {1:+}bbbbbbbbbb | 5578 {1:+}cccccccccccccccccccccccccccccccccccccccccccc^c | 5579 {1:~ }|*2 5580 | 5581 ]], 5582 } 5583 feed('05x$') 5584 screen:expect { 5585 grid = [[ 5586 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb| 5587 {1:+}bbbbb | 5588 {1:+}cccccccccccccccccccccccccccccccccccccccccccc^c | 5589 {1:~ }|*2 5590 | 5591 ]], 5592 } 5593 end) 5594 5595 it('before double-width char that wraps', function() 5596 exec([[ 5597 call setline(1, repeat('a', 40) .. '口' .. '12345') 5598 normal! $ 5599 ]]) 5600 api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(9) } }, virt_text_pos = 'inline' }) 5601 screen:expect([[ 5602 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| 5603 口1234^5 | 5604 | 5605 ]]) 5606 feed('g0') 5607 screen:expect([[ 5608 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| 5609 ^口12345 | 5610 | 5611 ]]) 5612 command('set showbreak=+++') 5613 screen:expect([[ 5614 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| 5615 {1:+++}^口12345 | 5616 | 5617 ]]) 5618 end) 5619 5620 it('cursor position is correct if end_row or end_col is specified', function() 5621 screen:try_resize(50, 8) 5622 api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48), ('c'):rep(48), ('d'):rep(48) }) 5623 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, virt_text_pos = 'inline', virt_text = { { 'I1', 'NonText' } } }) 5624 api.nvim_buf_set_extmark(0, ns, 3, 0, { end_col = 2, virt_text_pos = 'inline', virt_text = { { 'I2', 'NonText' } } }) 5625 feed('$') 5626 screen:expect([[ 5627 {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^a| 5628 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | 5629 cccccccccccccccccccccccccccccccccccccccccccccccc | 5630 {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| 5631 {1:~ }|*3 5632 | 5633 ]]) 5634 feed('j') 5635 screen:expect([[ 5636 {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 5637 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b | 5638 cccccccccccccccccccccccccccccccccccccccccccccccc | 5639 {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| 5640 {1:~ }|*3 5641 | 5642 ]]) 5643 feed('j') 5644 screen:expect([[ 5645 {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 5646 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | 5647 ccccccccccccccccccccccccccccccccccccccccccccccc^c | 5648 {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| 5649 {1:~ }|*3 5650 | 5651 ]]) 5652 feed('j') 5653 screen:expect([[ 5654 {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 5655 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | 5656 cccccccccccccccccccccccccccccccccccccccccccccccc | 5657 {1:I2}ddddddddddddddddddddddddddddddddddddddddddddddd^d| 5658 {1:~ }|*3 5659 | 5660 ]]) 5661 end) 5662 5663 it('is redrawn correctly after delete or redo #27370', function() 5664 screen:try_resize(50, 12) 5665 exec([[ 5666 call setline(1, ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff']) 5667 call setline(3, repeat('c', winwidth(0) - 1)) 5668 ]]) 5669 api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { '!!!' } }, virt_text_pos = 'inline' }) 5670 feed('j') 5671 local before_delete = [[ 5672 aaa | 5673 !!!^bbb | 5674 ccccccccccccccccccccccccccccccccccccccccccccccccc | 5675 ddd | 5676 eee | 5677 fff | 5678 {1:~ }|*5 5679 | 5680 ]] 5681 screen:expect(before_delete) 5682 feed('dd') 5683 local after_delete = [[ 5684 aaa | 5685 !!!^ccccccccccccccccccccccccccccccccccccccccccccccc| 5686 cc | 5687 ddd | 5688 eee | 5689 fff | 5690 {1:~ }|*5 5691 | 5692 ]] 5693 screen:expect(after_delete) 5694 command('silent undo') 5695 screen:expect(before_delete) 5696 command('silent redo') 5697 screen:expect(after_delete) 5698 command('silent undo') 5699 screen:expect(before_delete) 5700 command('set report=100') 5701 feed('yypk2P') 5702 before_delete = [[ 5703 aaa | 5704 ^bbb | 5705 bbb | 5706 !!!bbb | 5707 bbb | 5708 ccccccccccccccccccccccccccccccccccccccccccccccccc | 5709 ddd | 5710 eee | 5711 fff | 5712 {1:~ }|*2 5713 | 5714 ]] 5715 screen:expect(before_delete) 5716 feed('4dd') 5717 screen:expect(after_delete) 5718 command('silent undo') 5719 screen:expect(before_delete) 5720 command('silent redo') 5721 screen:expect(after_delete) 5722 end) 5723 5724 it('cursor position is correct with invalidated inline virt text', function() 5725 screen:try_resize(50, 8) 5726 api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48) }) 5727 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text_pos = 'inline', virt_text = { { 'INLINE', 'NonText' } }, invalidate = true }) 5728 screen:expect([[ 5729 {1:INLINE}^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| 5730 aaaa | 5731 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | 5732 {1:~ }|*4 5733 | 5734 ]]) 5735 feed('dd$') 5736 screen:expect([[ 5737 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b | 5738 {1:~ }|*6 5739 | 5740 ]]) 5741 end) 5742 5743 it('line size is correct with inline virt text at EOL and showbreak', function() 5744 screen:try_resize(50, 8) 5745 insert(('0123456789'):rep(5) .. '\nfoo\nbar') 5746 api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { ('x'):rep(145), 'ErrorMsg' } }, virt_text_pos = 'inline' }) 5747 5748 command([[set cursorline scrolloff=0 showbreak=>\ smoothscroll]]) 5749 screen:expect([[ 5750 01234567890123456789012345678901234567890123456789| 5751 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3 5752 {1:> }{4:x} | 5753 foo | 5754 {22:ba^r }| 5755 | 5756 ]]) 5757 eq(5, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all) 5758 feed('<C-E>') 5759 screen:expect([[ 5760 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3 5761 {1:> }{4:x} | 5762 foo | 5763 {22:ba^r }| 5764 {1:~ }| 5765 | 5766 ]]) 5767 feed('<C-E>') 5768 screen:expect([[ 5769 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2 5770 {1:> }{4:x} | 5771 foo | 5772 {22:ba^r }| 5773 {1:~ }|*2 5774 | 5775 ]]) 5776 feed('<C-E>') 5777 screen:expect([[ 5778 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}| 5779 {1:> }{4:x} | 5780 foo | 5781 {22:ba^r }| 5782 {1:~ }|*3 5783 | 5784 ]]) 5785 feed('<C-E>') 5786 screen:expect([[ 5787 {1:> }{4:x} | 5788 foo | 5789 {22:ba^r }| 5790 {1:~ }|*4 5791 | 5792 ]]) 5793 feed('<C-E>') 5794 screen:expect([[ 5795 foo | 5796 {22:ba^r }| 5797 {1:~ }|*5 5798 | 5799 ]]) 5800 5801 feed('gg$xG$') 5802 screen:expect([[ 5803 0123456789012345678901234567890123456789012345678{4:x}| 5804 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3 5805 foo | 5806 {22:ba^r }| 5807 {1:~ }| 5808 | 5809 ]]) 5810 eq(4, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all) 5811 feed('<C-E>') 5812 screen:expect([[ 5813 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3 5814 foo | 5815 {22:ba^r }| 5816 {1:~ }|*2 5817 | 5818 ]]) 5819 feed('<C-E>') 5820 screen:expect([[ 5821 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2 5822 foo | 5823 {22:ba^r }| 5824 {1:~ }|*3 5825 | 5826 ]]) 5827 feed('<C-E>') 5828 screen:expect([[ 5829 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}| 5830 foo | 5831 {22:ba^r }| 5832 {1:~ }|*4 5833 | 5834 ]]) 5835 feed('<C-E>') 5836 screen:expect([[ 5837 foo | 5838 {22:ba^r }| 5839 {1:~ }|*5 5840 | 5841 ]]) 5842 5843 feed('zb') 5844 command('set list listchars=eol:$') 5845 screen:expect([[ 5846 0123456789012345678901234567890123456789012345678{4:x}| 5847 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3 5848 {1:> $} | 5849 foo{1:$} | 5850 {22:ba^r}{23:$}{22: }| 5851 | 5852 ]]) 5853 eq(5, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all) 5854 feed('<C-E>') 5855 screen:expect([[ 5856 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3 5857 {1:> $} | 5858 foo{1:$} | 5859 {22:ba^r}{23:$}{22: }| 5860 {1:~ }| 5861 | 5862 ]]) 5863 feed('<C-E>') 5864 screen:expect([[ 5865 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2 5866 {1:> $} | 5867 foo{1:$} | 5868 {22:ba^r}{23:$}{22: }| 5869 {1:~ }|*2 5870 | 5871 ]]) 5872 feed('<C-E>') 5873 screen:expect([[ 5874 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}| 5875 {1:> $} | 5876 foo{1:$} | 5877 {22:ba^r}{23:$}{22: }| 5878 {1:~ }|*3 5879 | 5880 ]]) 5881 feed('<C-E>') 5882 screen:expect([[ 5883 {1:> $} | 5884 foo{1:$} | 5885 {22:ba^r}{23:$}{22: }| 5886 {1:~ }|*4 5887 | 5888 ]]) 5889 feed('<C-E>') 5890 screen:expect([[ 5891 foo{1:$} | 5892 {22:ba^r}{23:$}{22: }| 5893 {1:~ }|*5 5894 | 5895 ]]) 5896 5897 feed('gg$xG$') 5898 screen:expect([[ 5899 012345678901234567890123456789012345678901234567{4:xx}| 5900 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2 5901 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}| 5902 foo{1:$} | 5903 {22:ba^r}{23:$}{22: }| 5904 {1:~ }| 5905 | 5906 ]]) 5907 eq(4, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all) 5908 feed('<C-E>') 5909 screen:expect([[ 5910 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2 5911 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}| 5912 foo{1:$} | 5913 {22:ba^r}{23:$}{22: }| 5914 {1:~ }|*2 5915 | 5916 ]]) 5917 feed('<C-E>') 5918 screen:expect([[ 5919 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}| 5920 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}| 5921 foo{1:$} | 5922 {22:ba^r}{23:$}{22: }| 5923 {1:~ }|*3 5924 | 5925 ]]) 5926 feed('<C-E>') 5927 screen:expect([[ 5928 {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}| 5929 foo{1:$} | 5930 {22:ba^r}{23:$}{22: }| 5931 {1:~ }|*4 5932 | 5933 ]]) 5934 feed('<C-E>') 5935 screen:expect([[ 5936 foo{1:$} | 5937 {22:ba^r}{23:$}{22: }| 5938 {1:~ }|*5 5939 | 5940 ]]) 5941 end) 5942 5943 it("virtcol('$') is correct with inline virt text at EOL", function() 5944 insert(('1234567890\n'):rep(6)) 5945 for _, v in ipairs({ { 2, 'a' }, { 3, 'ab' }, { 4, 'abc' }, { 5, 'abcd' }, { 6, 'αβγ口' } }) do 5946 local ln, tx = unpack(v) 5947 local co = fn.col({ ln, '$' }) 5948 eq(11, fn.virtcol({ ln, '$' })) 5949 api.nvim_buf_set_extmark(0, ns, ln - 1, co - 1, { virt_text = { { tx } }, virt_text_pos = 'inline' }) 5950 eq(11 + fn.strwidth(tx), fn.virtcol({ ln, '$' })) 5951 end 5952 end) 5953 end) 5954 5955 describe('decorations: virtual lines', function() 5956 local screen ---@type test.functional.ui.screen 5957 local ns ---@type integer 5958 5959 before_each(function() 5960 clear() 5961 screen = Screen.new(50, 12) 5962 screen:add_extra_attr_ids { 5963 [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow }, 5964 } 5965 5966 ns = api.nvim_create_namespace 'test' 5967 end) 5968 5969 local example_text2 = [[ 5970 if (h->n_buckets < new_n_buckets) { // expand 5971 khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); 5972 h->keys = new_keys; 5973 if (kh_is_map && val_size) { 5974 char *new_vals = krealloc( h->vals_buf, new_n_buckets * val_size); 5975 h->vals_buf = new_vals; 5976 } 5977 }]] 5978 5979 it('works with one line', function() 5980 insert(example_text2) 5981 feed '2gg' 5982 screen:expect { 5983 grid = [[ 5984 if (h->n_buckets < new_n_buckets) { // expand | 5985 ^khkey_t *new_keys = (khkey_t *)krealloc((void *)| 5986 h->keys, new_n_buckets * sizeof(khkey_t)); | 5987 h->keys = new_keys; | 5988 if (kh_is_map && val_size) { | 5989 char *new_vals = krealloc( h->vals_buf, new_n_| 5990 buckets * val_size); | 5991 h->vals_buf = new_vals; | 5992 } | 5993 } | 5994 {1:~ }| 5995 | 5996 ]], 5997 } 5998 5999 api.nvim_buf_set_extmark(0, ns, 1, 33, { 6000 virt_lines = { { { '>> ', 'NonText' }, { 'krealloc', 'Identifier' }, { ': change the size of an allocation' } } }, 6001 virt_lines_above = true, 6002 }) 6003 6004 screen:expect { 6005 grid = [[ 6006 if (h->n_buckets < new_n_buckets) { // expand | 6007 {1:>> }{25:krealloc}: change the size of an allocation | 6008 ^khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6009 h->keys, new_n_buckets * sizeof(khkey_t)); | 6010 h->keys = new_keys; | 6011 if (kh_is_map && val_size) { | 6012 char *new_vals = krealloc( h->vals_buf, new_n_| 6013 buckets * val_size); | 6014 h->vals_buf = new_vals; | 6015 } | 6016 } | 6017 | 6018 ]], 6019 } 6020 6021 feed '/krealloc<cr>' 6022 screen:expect { 6023 grid = [[ 6024 if (h->n_buckets < new_n_buckets) { // expand | 6025 {1:>> }{25:krealloc}: change the size of an allocation | 6026 khkey_t *new_keys = (khkey_t *){10:^krealloc}((void *)| 6027 h->keys, new_n_buckets * sizeof(khkey_t)); | 6028 h->keys = new_keys; | 6029 if (kh_is_map && val_size) { | 6030 char *new_vals = {10:krealloc}( h->vals_buf, new_n_| 6031 buckets * val_size); | 6032 h->vals_buf = new_vals; | 6033 } | 6034 } | 6035 /krealloc | 6036 ]], 6037 } 6038 6039 -- virtual line remains anchored to the extmark 6040 feed 'i<cr>' 6041 screen:expect { 6042 grid = [[ 6043 if (h->n_buckets < new_n_buckets) { // expand | 6044 khkey_t *new_keys = (khkey_t *) | 6045 {1:>> }{25:krealloc}: change the size of an allocation | 6046 {10:^krealloc}((void *)h->keys, new_n_buckets * sizeof(k| 6047 hkey_t)); | 6048 h->keys = new_keys; | 6049 if (kh_is_map && val_size) { | 6050 char *new_vals = {10:krealloc}( h->vals_buf, new_n_| 6051 buckets * val_size); | 6052 h->vals_buf = new_vals; | 6053 } | 6054 {5:-- INSERT --} | 6055 ]], 6056 } 6057 6058 feed '<esc>3+' 6059 screen:expect { 6060 grid = [[ 6061 if (h->n_buckets < new_n_buckets) { // expand | 6062 khkey_t *new_keys = (khkey_t *) | 6063 {1:>> }{25:krealloc}: change the size of an allocation | 6064 {10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k| 6065 hkey_t)); | 6066 h->keys = new_keys; | 6067 if (kh_is_map && val_size) { | 6068 ^char *new_vals = {10:krealloc}( h->vals_buf, new_n_| 6069 buckets * val_size); | 6070 h->vals_buf = new_vals; | 6071 } | 6072 | 6073 ]], 6074 } 6075 6076 api.nvim_buf_set_extmark(0, ns, 5, 0, { 6077 virt_lines = { { { '^^ REVIEW:', 'Todo' }, { ' new_vals variable seems unnecessary?', 'Comment' } } }, 6078 }) 6079 screen:expect { 6080 grid = [[ 6081 if (h->n_buckets < new_n_buckets) { // expand | 6082 khkey_t *new_keys = (khkey_t *) | 6083 {1:>> }{25:krealloc}: change the size of an allocation | 6084 {10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k| 6085 hkey_t)); | 6086 h->keys = new_keys; | 6087 if (kh_is_map && val_size) { | 6088 ^char *new_vals = {10:krealloc}( h->vals_buf, new_n_| 6089 buckets * val_size); | 6090 {100:^^ REVIEW:}{18: new_vals variable seems unnecessary?} | 6091 h->vals_buf = new_vals; | 6092 | 6093 ]], 6094 } 6095 6096 api.nvim_buf_clear_namespace(0, ns, 0, -1) 6097 screen:expect { 6098 grid = [[ 6099 if (h->n_buckets < new_n_buckets) { // expand | 6100 khkey_t *new_keys = (khkey_t *) | 6101 {10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k| 6102 hkey_t)); | 6103 h->keys = new_keys; | 6104 if (kh_is_map && val_size) { | 6105 ^char *new_vals = {10:krealloc}( h->vals_buf, new_n_| 6106 buckets * val_size); | 6107 h->vals_buf = new_vals; | 6108 } | 6109 } | 6110 | 6111 ]], 6112 } 6113 end) 6114 6115 it('works with text at the beginning of the buffer', function() 6116 insert(example_text2) 6117 feed 'gg' 6118 6119 screen:expect { 6120 grid = [[ 6121 ^if (h->n_buckets < new_n_buckets) { // expand | 6122 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6123 h->keys, new_n_buckets * sizeof(khkey_t)); | 6124 h->keys = new_keys; | 6125 if (kh_is_map && val_size) { | 6126 char *new_vals = krealloc( h->vals_buf, new_n_| 6127 buckets * val_size); | 6128 h->vals_buf = new_vals; | 6129 } | 6130 } | 6131 {1:~ }| 6132 | 6133 ]], 6134 } 6135 6136 api.nvim_buf_set_extmark(0, ns, 0, 0, { 6137 virt_lines = { 6138 { { 'refactor(khash): ', 'Special' }, { 'take size of values as parameter' } }, 6139 { { 'Author: Dev Devsson, ' }, { 'Tue Aug 31 10:13:37 2021', 'Comment' } }, 6140 }, 6141 virt_lines_above = true, 6142 right_gravity = false, 6143 }) 6144 6145 -- placing virt_text on topline does not automatically cause a scroll 6146 screen:expect { 6147 grid = [[ 6148 ^if (h->n_buckets < new_n_buckets) { // expand | 6149 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6150 h->keys, new_n_buckets * sizeof(khkey_t)); | 6151 h->keys = new_keys; | 6152 if (kh_is_map && val_size) { | 6153 char *new_vals = krealloc( h->vals_buf, new_n_| 6154 buckets * val_size); | 6155 h->vals_buf = new_vals; | 6156 } | 6157 } | 6158 {1:~ }| 6159 | 6160 ]], 6161 unchanged = true, 6162 } 6163 6164 feed '<c-b>' 6165 screen:expect { 6166 grid = [[ 6167 {16:refactor(khash): }take size of values as parameter | 6168 Author: Dev Devsson, {18:Tue Aug 31 10:13:37 2021} | 6169 if (h->n_buckets < new_n_buckets) { // expand | 6170 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6171 h->keys, new_n_buckets * sizeof(khkey_t)); | 6172 h->keys = new_keys; | 6173 if (kh_is_map && val_size) { | 6174 char *new_vals = krealloc( h->vals_buf, new_n_| 6175 buckets * val_size); | 6176 h->vals_buf = new_vals; | 6177 ^} | 6178 | 6179 ]], 6180 } 6181 end) 6182 6183 it('works with text at the end of the buffer', function() 6184 insert(example_text2) 6185 feed 'G' 6186 6187 screen:expect { 6188 grid = [[ 6189 if (h->n_buckets < new_n_buckets) { // expand | 6190 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6191 h->keys, new_n_buckets * sizeof(khkey_t)); | 6192 h->keys = new_keys; | 6193 if (kh_is_map && val_size) { | 6194 char *new_vals = krealloc( h->vals_buf, new_n_| 6195 buckets * val_size); | 6196 h->vals_buf = new_vals; | 6197 } | 6198 ^} | 6199 {1:~ }| 6200 | 6201 ]], 6202 } 6203 6204 local id = api.nvim_buf_set_extmark(0, ns, 7, 0, { 6205 virt_lines = { { { 'Grugg' } } }, 6206 right_gravity = false, 6207 }) 6208 6209 screen:expect { 6210 grid = [[ 6211 if (h->n_buckets < new_n_buckets) { // expand | 6212 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6213 h->keys, new_n_buckets * sizeof(khkey_t)); | 6214 h->keys = new_keys; | 6215 if (kh_is_map && val_size) { | 6216 char *new_vals = krealloc( h->vals_buf, new_n_| 6217 buckets * val_size); | 6218 h->vals_buf = new_vals; | 6219 } | 6220 ^} | 6221 Grugg | 6222 | 6223 ]], 6224 } 6225 6226 screen:try_resize(50, 11) 6227 feed('gg') 6228 screen:expect { 6229 grid = [[ 6230 ^if (h->n_buckets < new_n_buckets) { // expand | 6231 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6232 h->keys, new_n_buckets * sizeof(khkey_t)); | 6233 h->keys = new_keys; | 6234 if (kh_is_map && val_size) { | 6235 char *new_vals = krealloc( h->vals_buf, new_n_| 6236 buckets * val_size); | 6237 h->vals_buf = new_vals; | 6238 } | 6239 } | 6240 | 6241 ]], 6242 } 6243 6244 feed('G<C-E>') 6245 screen:expect { 6246 grid = [[ 6247 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6248 h->keys, new_n_buckets * sizeof(khkey_t)); | 6249 h->keys = new_keys; | 6250 if (kh_is_map && val_size) { | 6251 char *new_vals = krealloc( h->vals_buf, new_n_| 6252 buckets * val_size); | 6253 h->vals_buf = new_vals; | 6254 } | 6255 ^} | 6256 Grugg | 6257 | 6258 ]], 6259 } 6260 6261 feed('gg') 6262 screen:expect { 6263 grid = [[ 6264 ^if (h->n_buckets < new_n_buckets) { // expand | 6265 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6266 h->keys, new_n_buckets * sizeof(khkey_t)); | 6267 h->keys = new_keys; | 6268 if (kh_is_map && val_size) { | 6269 char *new_vals = krealloc( h->vals_buf, new_n_| 6270 buckets * val_size); | 6271 h->vals_buf = new_vals; | 6272 } | 6273 } | 6274 | 6275 ]], 6276 } 6277 6278 screen:try_resize(50, 12) 6279 feed('G') 6280 screen:expect { 6281 grid = [[ 6282 if (h->n_buckets < new_n_buckets) { // expand | 6283 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6284 h->keys, new_n_buckets * sizeof(khkey_t)); | 6285 h->keys = new_keys; | 6286 if (kh_is_map && val_size) { | 6287 char *new_vals = krealloc( h->vals_buf, new_n_| 6288 buckets * val_size); | 6289 h->vals_buf = new_vals; | 6290 } | 6291 ^} | 6292 Grugg | 6293 | 6294 ]], 6295 } 6296 6297 api.nvim_buf_del_extmark(0, ns, id) 6298 screen:expect { 6299 grid = [[ 6300 if (h->n_buckets < new_n_buckets) { // expand | 6301 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6302 h->keys, new_n_buckets * sizeof(khkey_t)); | 6303 h->keys = new_keys; | 6304 if (kh_is_map && val_size) { | 6305 char *new_vals = krealloc( h->vals_buf, new_n_| 6306 buckets * val_size); | 6307 h->vals_buf = new_vals; | 6308 } | 6309 ^} | 6310 {1:~ }| 6311 | 6312 ]], 6313 } 6314 end) 6315 6316 it('works beyond end of the buffer with virt_lines_above', function() 6317 insert(example_text2) 6318 feed 'G' 6319 6320 screen:expect { 6321 grid = [[ 6322 if (h->n_buckets < new_n_buckets) { // expand | 6323 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6324 h->keys, new_n_buckets * sizeof(khkey_t)); | 6325 h->keys = new_keys; | 6326 if (kh_is_map && val_size) { | 6327 char *new_vals = krealloc( h->vals_buf, new_n_| 6328 buckets * val_size); | 6329 h->vals_buf = new_vals; | 6330 } | 6331 ^} | 6332 {1:~ }| 6333 | 6334 ]], 6335 } 6336 6337 local id = api.nvim_buf_set_extmark(0, ns, 8, 0, { 6338 virt_lines = { { { 'Grugg' } } }, 6339 virt_lines_above = true, 6340 }) 6341 6342 screen:expect { 6343 grid = [[ 6344 if (h->n_buckets < new_n_buckets) { // expand | 6345 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6346 h->keys, new_n_buckets * sizeof(khkey_t)); | 6347 h->keys = new_keys; | 6348 if (kh_is_map && val_size) { | 6349 char *new_vals = krealloc( h->vals_buf, new_n_| 6350 buckets * val_size); | 6351 h->vals_buf = new_vals; | 6352 } | 6353 ^} | 6354 Grugg | 6355 | 6356 ]], 6357 } 6358 6359 feed('dd') 6360 screen:expect { 6361 grid = [[ 6362 if (h->n_buckets < new_n_buckets) { // expand | 6363 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6364 h->keys, new_n_buckets * sizeof(khkey_t)); | 6365 h->keys = new_keys; | 6366 if (kh_is_map && val_size) { | 6367 char *new_vals = krealloc( h->vals_buf, new_n_| 6368 buckets * val_size); | 6369 h->vals_buf = new_vals; | 6370 ^} | 6371 Grugg | 6372 {1:~ }| 6373 | 6374 ]], 6375 } 6376 6377 feed('dk') 6378 screen:expect { 6379 grid = [[ 6380 if (h->n_buckets < new_n_buckets) { // expand | 6381 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6382 h->keys, new_n_buckets * sizeof(khkey_t)); | 6383 h->keys = new_keys; | 6384 if (kh_is_map && val_size) { | 6385 ^char *new_vals = krealloc( h->vals_buf, new_n_| 6386 buckets * val_size); | 6387 Grugg | 6388 {1:~ }|*3 6389 | 6390 ]], 6391 } 6392 6393 feed('dgg') 6394 screen:expect { 6395 grid = [[ 6396 ^ | 6397 Grugg | 6398 {1:~ }|*9 6399 --No lines in buffer-- | 6400 ]], 6401 } 6402 6403 api.nvim_buf_del_extmark(0, ns, id) 6404 screen:expect { 6405 grid = [[ 6406 ^ | 6407 {1:~ }|*10 6408 --No lines in buffer-- | 6409 ]], 6410 } 6411 end) 6412 6413 it('does not cause syntax ml_get error at the end of a buffer #17816', function() 6414 command([[syntax region foo keepend start='^foo' end='^$']]) 6415 command('syntax sync minlines=100') 6416 insert('foo') 6417 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'bar', 'Comment' } } } }) 6418 screen:expect([[ 6419 fo^o | 6420 {18:bar} | 6421 {1:~ }|*9 6422 | 6423 ]]) 6424 end) 6425 6426 it('works with a block scrolling up', function() 6427 screen:try_resize(30, 7) 6428 insert('aa\nbb\ncc\ndd\nee\nff\ngg\nhh') 6429 feed 'gg' 6430 6431 api.nvim_buf_set_extmark(0, ns, 6, 0, { 6432 virt_lines = { 6433 { { 'they see me' } }, 6434 { { 'scrolling', 'Special' } }, 6435 { { 'they' } }, 6436 { { "hatin'", 'Special' } }, 6437 }, 6438 }) 6439 6440 screen:expect { 6441 grid = [[ 6442 ^aa | 6443 bb | 6444 cc | 6445 dd | 6446 ee | 6447 ff | 6448 | 6449 ]], 6450 } 6451 6452 feed '<c-e>' 6453 screen:expect { 6454 grid = [[ 6455 ^bb | 6456 cc | 6457 dd | 6458 ee | 6459 ff | 6460 gg | 6461 | 6462 ]], 6463 } 6464 6465 feed '<c-e>' 6466 screen:expect { 6467 grid = [[ 6468 ^cc | 6469 dd | 6470 ee | 6471 ff | 6472 gg | 6473 they see me | 6474 | 6475 ]], 6476 } 6477 6478 feed '<c-e>' 6479 screen:expect { 6480 grid = [[ 6481 ^dd | 6482 ee | 6483 ff | 6484 gg | 6485 they see me | 6486 {16:scrolling} | 6487 | 6488 ]], 6489 } 6490 6491 feed '<c-e>' 6492 screen:expect { 6493 grid = [[ 6494 ^ee | 6495 ff | 6496 gg | 6497 they see me | 6498 {16:scrolling} | 6499 they | 6500 | 6501 ]], 6502 } 6503 6504 feed '<c-e>' 6505 screen:expect { 6506 grid = [[ 6507 ^ff | 6508 gg | 6509 they see me | 6510 {16:scrolling} | 6511 they | 6512 {16:hatin'} | 6513 | 6514 ]], 6515 } 6516 6517 feed '<c-e>' 6518 screen:expect { 6519 grid = [[ 6520 ^gg | 6521 they see me | 6522 {16:scrolling} | 6523 they | 6524 {16:hatin'} | 6525 hh | 6526 | 6527 ]], 6528 } 6529 6530 feed '<c-e>' 6531 screen:expect { 6532 grid = [[ 6533 they see me | 6534 {16:scrolling} | 6535 they | 6536 {16:hatin'} | 6537 ^hh | 6538 {1:~ }| 6539 | 6540 ]], 6541 } 6542 6543 feed '<c-e>' 6544 screen:expect { 6545 grid = [[ 6546 {16:scrolling} | 6547 they | 6548 {16:hatin'} | 6549 ^hh | 6550 {1:~ }|*2 6551 | 6552 ]], 6553 } 6554 6555 feed '<c-e>' 6556 screen:expect { 6557 grid = [[ 6558 they | 6559 {16:hatin'} | 6560 ^hh | 6561 {1:~ }|*3 6562 | 6563 ]], 6564 } 6565 6566 feed '<c-e>' 6567 screen:expect { 6568 grid = [[ 6569 {16:hatin'} | 6570 ^hh | 6571 {1:~ }|*4 6572 | 6573 ]], 6574 } 6575 6576 feed '<c-e>' 6577 screen:expect { 6578 grid = [[ 6579 ^hh | 6580 {1:~ }|*5 6581 | 6582 ]], 6583 } 6584 end) 6585 6586 it('works with sign and numbercolumns', function() 6587 insert(example_text2) 6588 feed 'gg' 6589 command 'set number signcolumn=yes' 6590 screen:expect([[ 6591 {7: }{8: 1 }^if (h->n_buckets < new_n_buckets) { // expan| 6592 {7: }{8: }d | 6593 {7: }{8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v| 6594 {7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_| 6595 {7: }{8: }t)); | 6596 {7: }{8: 3 } h->keys = new_keys; | 6597 {7: }{8: 4 } if (kh_is_map && val_size) { | 6598 {7: }{8: 5 } char *new_vals = krealloc( h->vals_buf, | 6599 {7: }{8: }new_n_buckets * val_size); | 6600 {7: }{8: 6 } h->vals_buf = new_vals; | 6601 {7: }{8: 7 } } | 6602 | 6603 ]]) 6604 6605 local markid = api.nvim_buf_set_extmark(0, ns, 2, 0, { 6606 virt_lines = { 6607 { { 'Some special', 'Special' } }, 6608 { { 'remark about codes', 'Comment' } }, 6609 }, 6610 }) 6611 6612 screen:expect([[ 6613 {7: }{8: 1 }^if (h->n_buckets < new_n_buckets) { // expan| 6614 {7: }{8: }d | 6615 {7: }{8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v| 6616 {7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_| 6617 {7: }{8: }t)); | 6618 {7: }{8: 3 } h->keys = new_keys; | 6619 {7: }{8: }{16:Some special} | 6620 {7: }{8: }{18:remark about codes} | 6621 {7: }{8: 4 } if (kh_is_map && val_size) { | 6622 {7: }{8: 5 } char *new_vals = krealloc( h->vals_buf, | 6623 {7: }{8: }new_n_buckets * val_size); | 6624 | 6625 ]]) 6626 6627 api.nvim_buf_set_extmark(0, ns, 2, 0, { 6628 virt_lines = { 6629 { { 'Some special', 'Special' } }, 6630 { { 'remark about codes', 'Comment' } }, 6631 }, 6632 virt_lines_leftcol = true, 6633 id = markid, 6634 }) 6635 screen:expect([[ 6636 {7: }{8: 1 }^if (h->n_buckets < new_n_buckets) { // expan| 6637 {7: }{8: }d | 6638 {7: }{8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v| 6639 {7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_| 6640 {7: }{8: }t)); | 6641 {7: }{8: 3 } h->keys = new_keys; | 6642 {16:Some special} | 6643 {18:remark about codes} | 6644 {7: }{8: 4 } if (kh_is_map && val_size) { | 6645 {7: }{8: 5 } char *new_vals = krealloc( h->vals_buf, | 6646 {7: }{8: }new_n_buckets * val_size); | 6647 | 6648 ]]) 6649 6650 command('set nonumber relativenumber') 6651 screen:expect([[ 6652 {7: }{8: 0 }^if (h->n_buckets < new_n_buckets) { // expan| 6653 {7: }{8: }d | 6654 {7: }{8: 1 } khkey_t *new_keys = (khkey_t *)krealloc((v| 6655 {7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_| 6656 {7: }{8: }t)); | 6657 {7: }{8: 2 } h->keys = new_keys; | 6658 {16:Some special} | 6659 {18:remark about codes} | 6660 {7: }{8: 3 } if (kh_is_map && val_size) { | 6661 {7: }{8: 4 } char *new_vals = krealloc( h->vals_buf, | 6662 {7: }{8: }new_n_buckets * val_size); | 6663 | 6664 ]]) 6665 6666 -- 'relativenumber' is redrawn with virt_lines_leftcol #34649 6667 feed('j') 6668 screen:expect([[ 6669 {7: }{8: 1 }if (h->n_buckets < new_n_buckets) { // expan| 6670 {7: }{8: }d | 6671 {7: }{8: 0 }^ khkey_t *new_keys = (khkey_t *)krealloc((v| 6672 {7: }{8: }oid *)h->keys, new_n_buckets * sizeof(khkey_| 6673 {7: }{8: }t)); | 6674 {7: }{8: 1 } h->keys = new_keys; | 6675 {16:Some special} | 6676 {18:remark about codes} | 6677 {7: }{8: 2 } if (kh_is_map && val_size) { | 6678 {7: }{8: 3 } char *new_vals = krealloc( h->vals_buf, | 6679 {7: }{8: }new_n_buckets * val_size); | 6680 | 6681 ]]) 6682 end) 6683 6684 it('works with hard TABs', function() 6685 insert(example_text2) 6686 feed 'gg' 6687 api.nvim_buf_set_extmark(0, ns, 1, 0, { 6688 virt_lines = { { { '>>', 'NonText' }, { '\tvery\ttabby', 'Identifier' }, { 'text\twith\ttabs' } } }, 6689 }) 6690 screen:expect { 6691 grid = [[ 6692 ^if (h->n_buckets < new_n_buckets) { // expand | 6693 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6694 h->keys, new_n_buckets * sizeof(khkey_t)); | 6695 {1:>>}{25: very tabby}text with tabs | 6696 h->keys = new_keys; | 6697 if (kh_is_map && val_size) { | 6698 char *new_vals = krealloc( h->vals_buf, new_n_| 6699 buckets * val_size); | 6700 h->vals_buf = new_vals; | 6701 } | 6702 } | 6703 | 6704 ]], 6705 } 6706 6707 command 'set tabstop=4' 6708 screen:expect { 6709 grid = [[ 6710 ^if (h->n_buckets < new_n_buckets) { // expand | 6711 khkey_t *new_keys = (khkey_t *)krealloc((void *)| 6712 h->keys, new_n_buckets * sizeof(khkey_t)); | 6713 {1:>>}{25: very tabby}text with tabs | 6714 h->keys = new_keys; | 6715 if (kh_is_map && val_size) { | 6716 char *new_vals = krealloc( h->vals_buf, new_n_| 6717 buckets * val_size); | 6718 h->vals_buf = new_vals; | 6719 } | 6720 } | 6721 | 6722 ]], 6723 } 6724 6725 command 'set number' 6726 screen:expect { 6727 grid = [[ 6728 {8: 1 }^if (h->n_buckets < new_n_buckets) { // expand | 6729 {8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((voi| 6730 {8: }d *)h->keys, new_n_buckets * sizeof(khkey_t));| 6731 {8: }{1:>>}{25: very tabby}text with tabs | 6732 {8: 3 } h->keys = new_keys; | 6733 {8: 4 } if (kh_is_map && val_size) { | 6734 {8: 5 } char *new_vals = krealloc( h->vals_buf, ne| 6735 {8: }w_n_buckets * val_size); | 6736 {8: 6 } h->vals_buf = new_vals; | 6737 {8: 7 } } | 6738 {8: 8 }} | 6739 | 6740 ]], 6741 } 6742 6743 command 'set tabstop&' 6744 screen:expect { 6745 grid = [[ 6746 {8: 1 }^if (h->n_buckets < new_n_buckets) { // expand | 6747 {8: 2 } khkey_t *new_keys = (khkey_t *)krealloc((voi| 6748 {8: }d *)h->keys, new_n_buckets * sizeof(khkey_t));| 6749 {8: }{1:>>}{25: very tabby}text with tabs | 6750 {8: 3 } h->keys = new_keys; | 6751 {8: 4 } if (kh_is_map && val_size) { | 6752 {8: 5 } char *new_vals = krealloc( h->vals_buf, ne| 6753 {8: }w_n_buckets * val_size); | 6754 {8: 6 } h->vals_buf = new_vals; | 6755 {8: 7 } } | 6756 {8: 8 }} | 6757 | 6758 ]], 6759 } 6760 end) 6761 6762 it('scrolls horizontally with virt_lines_overflow = "scroll" #31000', function() 6763 command('set nowrap signcolumn=yes') 6764 insert('abcdefghijklmnopqrstuvwxyz') 6765 api.nvim_buf_set_extmark(0, ns, 0, 0, { 6766 virt_lines = { 6767 { { '12α口β̳γ̲=', 'Special' }, { '❤️345678', 'Special' } }, 6768 { { '123\t45\t678', 'NonText' } }, 6769 }, 6770 virt_lines_overflow = 'scroll', 6771 }) 6772 screen:expect([[ 6773 {7: }abcdefghijklmnopqrstuvwxy^z | 6774 {7: }{16:12α口β̳γ̲=❤️345678} | 6775 {7: }{1:123 45 678} | 6776 {1:~ }|*8 6777 | 6778 ]]) 6779 feed('zl') 6780 screen:expect([[ 6781 {7: }bcdefghijklmnopqrstuvwxy^z | 6782 {7: }{16:2α口β̳γ̲=❤️345678} | 6783 {7: }{1:23 45 678} | 6784 {1:~ }|*8 6785 | 6786 ]]) 6787 feed('zl') 6788 screen:expect([[ 6789 {7: }cdefghijklmnopqrstuvwxy^z | 6790 {7: }{16:α口β̳γ̲=❤️345678} | 6791 {7: }{1:3 45 678} | 6792 {1:~ }|*8 6793 | 6794 ]]) 6795 feed('zl') 6796 screen:expect([[ 6797 {7: }defghijklmnopqrstuvwxy^z | 6798 {7: }{16:口β̳γ̲=❤️345678} | 6799 {7: }{1: 45 678} | 6800 {1:~ }|*8 6801 | 6802 ]]) 6803 feed('zl') 6804 screen:expect([[ 6805 {7: }efghijklmnopqrstuvwxy^z | 6806 {7: }{16: β̳γ̲=❤️345678} | 6807 {7: }{1: 45 678} | 6808 {1:~ }|*8 6809 | 6810 ]]) 6811 feed('zl') 6812 screen:expect([[ 6813 {7: }fghijklmnopqrstuvwxy^z | 6814 {7: }{16:β̳γ̲=❤️345678} | 6815 {7: }{1: 45 678} | 6816 {1:~ }|*8 6817 | 6818 ]]) 6819 feed('zl') 6820 screen:expect([[ 6821 {7: }ghijklmnopqrstuvwxy^z | 6822 {7: }{16:γ̲=❤️345678} | 6823 {7: }{1: 45 678} | 6824 {1:~ }|*8 6825 | 6826 ]]) 6827 feed('zl') 6828 screen:expect([[ 6829 {7: }hijklmnopqrstuvwxy^z | 6830 {7: }{16:=❤️345678} | 6831 {7: }{1: 45 678} | 6832 {1:~ }|*8 6833 | 6834 ]]) 6835 feed('zl') 6836 screen:expect([[ 6837 {7: }ijklmnopqrstuvwxy^z | 6838 {7: }{16:❤️345678} | 6839 {7: }{1:45 678} | 6840 {1:~ }|*8 6841 | 6842 ]]) 6843 feed('zl') 6844 screen:expect([[ 6845 {7: }jklmnopqrstuvwxy^z | 6846 {7: }{16: 345678} | 6847 {7: }{1:5 678} | 6848 {1:~ }|*8 6849 | 6850 ]]) 6851 feed('zl') 6852 screen:expect([[ 6853 {7: }klmnopqrstuvwxy^z | 6854 {7: }{16:345678} | 6855 {7: }{1: 678} | 6856 {1:~ }|*8 6857 | 6858 ]]) 6859 feed('zl') 6860 screen:expect([[ 6861 {7: }lmnopqrstuvwxy^z | 6862 {7: }{16:45678} | 6863 {7: }{1: 678} | 6864 {1:~ }|*8 6865 | 6866 ]]) 6867 feed('zl') 6868 screen:expect([[ 6869 {7: }mnopqrstuvwxy^z | 6870 {7: }{16:5678} | 6871 {7: }{1: 678} | 6872 {1:~ }|*8 6873 | 6874 ]]) 6875 api.nvim_buf_set_extmark(0, ns, 0, 1, { 6876 virt_lines = { { { '123\t45\t67', 'NonText' } } }, 6877 virt_lines_leftcol = true, 6878 virt_lines_overflow = 'trunc', 6879 }) 6880 api.nvim_buf_set_extmark(0, ns, 0, 2, { 6881 virt_lines = { { { '123\t45\t6', 'NonText' } } }, 6882 virt_lines_leftcol = false, 6883 virt_lines_overflow = 'trunc', 6884 }) 6885 screen:expect([[ 6886 {7: }mnopqrstuvwxy^z | 6887 {7: }{16:5678} | 6888 {7: }{1: 678} | 6889 {1:123 45 67} | 6890 {7: }{1:123 45 6} | 6891 {1:~ }|*6 6892 | 6893 ]]) 6894 end) 6895 6896 it('does not show twice if end_row or end_col is specified #18622', function() 6897 screen:try_resize(50, 8) 6898 insert([[ 6899 aaa 6900 bbb 6901 ccc 6902 ddd]]) 6903 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, virt_lines = { { { 'VIRT LINE 1', 'NonText' } } } }) 6904 api.nvim_buf_set_extmark(0, ns, 3, 0, { end_col = 2, virt_lines = { { { 'VIRT LINE 2', 'NonText' } } } }) 6905 screen:expect { 6906 grid = [[ 6907 aaa | 6908 {1:VIRT LINE 1} | 6909 bbb | 6910 ccc | 6911 dd^d | 6912 {1:VIRT LINE 2} | 6913 {1:~ }| 6914 | 6915 ]], 6916 } 6917 end) 6918 6919 it('works with rightleft', function() 6920 screen:try_resize(50, 8) 6921 insert([[ 6922 aaa 6923 bbb 6924 ccc 6925 ddd]]) 6926 command('set number rightleft') 6927 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT LINE 1', 'NonText' } } }, virt_lines_leftcol = true }) 6928 api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'VIRT LINE 2', 'NonText' } } } }) 6929 screen:expect { 6930 grid = [[ 6931 aaa{8: 1 }| 6932 {1:1 ENIL TRIV}| 6933 bbb{8: 2 }| 6934 ccc{8: 3 }| 6935 ^ddd{8: 4 }| 6936 {1:2 ENIL TRIV}{8: }| 6937 {1: ~}| 6938 | 6939 ]], 6940 } 6941 end) 6942 6943 it('works when using dd or yyp #23915 #23916', function() 6944 insert([[ 6945 line1 6946 line2 6947 line3 6948 line4 6949 line5]]) 6950 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'foo' } }, { { 'bar' } }, { { 'baz' } } } }) 6951 screen:expect { 6952 grid = [[ 6953 line1 | 6954 foo | 6955 bar | 6956 baz | 6957 line2 | 6958 line3 | 6959 line4 | 6960 line^5 | 6961 {1:~ }|*3 6962 | 6963 ]], 6964 } 6965 6966 feed('gg') 6967 feed('yyp') 6968 screen:expect { 6969 grid = [[ 6970 line1 | 6971 foo | 6972 bar | 6973 baz | 6974 ^line1 | 6975 line2 | 6976 line3 | 6977 line4 | 6978 line5 | 6979 {1:~ }|*2 6980 | 6981 ]], 6982 } 6983 6984 feed('dd') 6985 screen:expect { 6986 grid = [[ 6987 line1 | 6988 foo | 6989 bar | 6990 baz | 6991 ^line2 | 6992 line3 | 6993 line4 | 6994 line5 | 6995 {1:~ }|*3 6996 | 6997 ]], 6998 } 6999 7000 feed('kdd') 7001 screen:expect([[ 7002 ^line2 | 7003 foo | 7004 bar | 7005 baz | 7006 line3 | 7007 line4 | 7008 line5 | 7009 {1:~ }|*4 7010 | 7011 ]]) 7012 end) 7013 7014 it('does not break cursor position with concealcursor #27887', function() 7015 command('vsplit') 7016 insert('\n') 7017 api.nvim_set_option_value('conceallevel', 2, {}) 7018 api.nvim_set_option_value('concealcursor', 'niv', {}) 7019 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT1' } }, { { 'VIRT2' } } } }) 7020 screen:expect([[ 7021 │ | 7022 VIRT1 │VIRT1 | 7023 VIRT2 │VIRT2 | 7024 ^ │ | 7025 {1:~ }│{1:~ }|*6 7026 {3:[No Name] [+] }{2:[No Name] [+] }| 7027 | 7028 ]]) 7029 end) 7030 7031 it('works with full page scrolling #28290', function() 7032 screen:try_resize(20, 8) 7033 command('call setline(1, range(20))') 7034 api.nvim_buf_set_extmark(0, ns, 10, 0, { virt_lines = { { { 'VIRT1' } }, { { 'VIRT2' } } } }) 7035 screen:expect([[ 7036 ^0 | 7037 1 | 7038 2 | 7039 3 | 7040 4 | 7041 5 | 7042 6 | 7043 | 7044 ]]) 7045 feed('<C-F>') 7046 screen:expect([[ 7047 ^5 | 7048 6 | 7049 7 | 7050 8 | 7051 9 | 7052 10 | 7053 VIRT1 | 7054 | 7055 ]]) 7056 feed('<C-F>') 7057 screen:expect([[ 7058 ^10 | 7059 VIRT1 | 7060 VIRT2 | 7061 11 | 7062 12 | 7063 13 | 7064 14 | 7065 | 7066 ]]) 7067 feed('<C-F>') 7068 screen:expect([[ 7069 ^13 | 7070 14 | 7071 15 | 7072 16 | 7073 17 | 7074 18 | 7075 19 | 7076 | 7077 ]]) 7078 feed('<C-B>') 7079 screen:expect([[ 7080 10 | 7081 VIRT1 | 7082 VIRT2 | 7083 11 | 7084 12 | 7085 13 | 7086 ^14 | 7087 | 7088 ]]) 7089 feed('<C-B>') 7090 screen:expect([[ 7091 5 | 7092 6 | 7093 7 | 7094 8 | 7095 9 | 7096 ^10 | 7097 VIRT1 | 7098 | 7099 ]]) 7100 feed('<C-B>') 7101 screen:expect([[ 7102 0 | 7103 1 | 7104 2 | 7105 3 | 7106 4 | 7107 5 | 7108 ^6 | 7109 | 7110 ]]) 7111 end) 7112 7113 it('not drawn when invalid', function() 7114 api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' }) 7115 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT1' } } }, invalidate = true }) 7116 screen:expect({ 7117 grid = [[ 7118 ^foo | 7119 VIRT1 | 7120 bar | 7121 {1:~ }|*8 7122 | 7123 ]], 7124 }) 7125 feed('dd') 7126 screen:expect({ 7127 grid = [[ 7128 ^bar | 7129 {1:~ }|*10 7130 | 7131 ]], 7132 }) 7133 end) 7134 7135 it("not revealed before skipcol scrolling up with 'smoothscroll'", function() 7136 api.nvim_set_option_value('smoothscroll', true, {}) 7137 api.nvim_buf_set_lines(0, 0, -1, false, { ('x'):rep(screen._width * 2) }) 7138 api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines_above = true, virt_lines = { { { 'VIRT1' } } } }) 7139 feed('<C-E>') 7140 screen:expect([[ 7141 {1:<<<}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x| 7142 {1:~ }|*10 7143 | 7144 ]]) 7145 feed('<C-Y>') 7146 screen:expect([[ 7147 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| 7148 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x| 7149 {1:~ }|*9 7150 | 7151 ]]) 7152 feed('<C-Y>') 7153 screen:expect([[ 7154 VIRT1 | 7155 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| 7156 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x| 7157 {1:~ }|*8 7158 | 7159 ]]) 7160 end) 7161 end) 7162 7163 describe('decorations: signs', function() 7164 local screen ---@type test.functional.ui.screen 7165 local ns ---@type integer 7166 7167 before_each(function() 7168 clear() 7169 screen = Screen.new(50, 10) 7170 screen:add_extra_attr_ids { 7171 [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow }, 7172 } 7173 7174 ns = api.nvim_create_namespace 'test' 7175 api.nvim_set_option_value('signcolumn', 'auto:9', {}) 7176 end) 7177 7178 local example_test3 = [[ 7179 l1 7180 l2 7181 l3 7182 l4 7183 l5 7184 ]] 7185 7186 it('can add a single sign (no end row)', function() 7187 insert(example_test3) 7188 feed 'gg' 7189 7190 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S' }) 7191 7192 screen:expect([[ 7193 {7: }^l1 | 7194 {7:S }l2 | 7195 {7: }l3 | 7196 {7: }l4 | 7197 {7: }l5 | 7198 {7: } | 7199 {1:~ }|*3 7200 | 7201 ]]) 7202 end) 7203 7204 it('can add a single sign (with end row)', function() 7205 insert(example_test3) 7206 feed 'gg' 7207 7208 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S', end_row = 1 }) 7209 7210 screen:expect([[ 7211 {7: }^l1 | 7212 {7:S }l2 | 7213 {7: }l3 | 7214 {7: }l4 | 7215 {7: }l5 | 7216 {7: } | 7217 {1:~ }|*3 7218 | 7219 ]]) 7220 end) 7221 7222 it('can add a single sign and text highlight', function() 7223 insert(example_test3) 7224 feed 'gg' 7225 7226 api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = 'S', hl_group = 'Todo', end_col = 1 }) 7227 screen:expect([[ 7228 {7: }^l1 | 7229 {7:S }{100:l}2 | 7230 {7: }l3 | 7231 {7: }l4 | 7232 {7: }l5 | 7233 {7: } | 7234 {1:~ }|*3 7235 | 7236 ]]) 7237 7238 api.nvim_buf_clear_namespace(0, ns, 0, -1) 7239 end) 7240 7241 it('can add multiple signs (single extmark)', function() 7242 insert(example_test3) 7243 feed 'gg' 7244 7245 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S', end_row = 2 }) 7246 7247 screen:expect([[ 7248 {7: }^l1 | 7249 {7:S }l2 | 7250 {7:S }l3 | 7251 {7: }l4 | 7252 {7: }l5 | 7253 {7: } | 7254 {1:~ }|*3 7255 | 7256 ]]) 7257 end) 7258 7259 it('can add multiple signs (multiple extmarks)', function() 7260 insert(example_test3) 7261 feed 'gg' 7262 7263 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S1' }) 7264 api.nvim_buf_set_extmark(0, ns, 3, -1, { sign_text = 'S2', end_row = 4 }) 7265 7266 screen:expect([[ 7267 {7: }^l1 | 7268 {7:S1}l2 | 7269 {7: }l3 | 7270 {7:S2}l4 | 7271 {7:S2}l5 | 7272 {7: } | 7273 {1:~ }|*3 7274 | 7275 ]]) 7276 end) 7277 7278 it('can add multiple signs (multiple extmarks) 2', function() 7279 insert(example_test3) 7280 feed 'gg' 7281 7282 api.nvim_buf_set_extmark(0, ns, 3, -1, { sign_text = 'S1' }) 7283 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2', end_row = 3 }) 7284 screen:expect([[ 7285 {7: }^l1 | 7286 {7:S2 }l2 | 7287 {7:S2 }l3 | 7288 {7:S2S1}l4 | 7289 {7: }l5 | 7290 {7: } | 7291 {1:~ }|*3 7292 | 7293 ]]) 7294 end) 7295 7296 it('can add multiple signs (multiple extmarks) 3', function() 7297 insert(example_test3) 7298 feed 'gg' 7299 7300 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S1', end_row = 2 }) 7301 api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S2', end_row = 3 }) 7302 7303 screen:expect([[ 7304 {7: }^l1 | 7305 {7:S1 }l2 | 7306 {7:S2S1}l3 | 7307 {7:S2 }l4 | 7308 {7: }l5 | 7309 {7: } | 7310 {1:~ }|*3 7311 | 7312 ]]) 7313 end) 7314 7315 it('can add multiple signs (multiple extmarks) 4', function() 7316 insert(example_test3) 7317 feed 'gg' 7318 7319 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', end_row = 0 }) 7320 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2', end_row = 1 }) 7321 7322 screen:expect([[ 7323 {7:S1}^l1 | 7324 {7:S2}l2 | 7325 {7: }l3 | 7326 {7: }l4 | 7327 {7: }l5 | 7328 {7: } | 7329 {1:~ }|*3 7330 | 7331 ]]) 7332 end) 7333 7334 it('works with old signs', function() 7335 insert(example_test3) 7336 feed 'gg' 7337 7338 n.command('sign define Oldsign text=x') 7339 n.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]]) 7340 7341 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' }) 7342 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2' }) 7343 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4' }) 7344 api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S5' }) 7345 7346 screen:expect([[ 7347 {7:S4S1}^l1 | 7348 {7:S2x }l2 | 7349 {7:S5 }l3 | 7350 {7: }l4 | 7351 {7: }l5 | 7352 {7: } | 7353 {1:~ }|*3 7354 | 7355 ]]) 7356 end) 7357 7358 it('works with old signs (with range)', function() 7359 insert(example_test3) 7360 feed 'gg' 7361 7362 n.command('sign define Oldsign text=x') 7363 n.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]]) 7364 7365 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' }) 7366 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2' }) 7367 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S3', end_row = 4 }) 7368 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4' }) 7369 api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S5' }) 7370 7371 screen:expect([[ 7372 {7:S4S3S1}^l1 | 7373 {7:S3S2x }l2 | 7374 {7:S5S3 }l3 | 7375 {7:S3 }l4 | 7376 {7:S3 }l5 | 7377 {7: } | 7378 {1:~ }|*3 7379 | 7380 ]]) 7381 end) 7382 7383 it('can add a ranged sign (with start out of view)', function() 7384 insert(example_test3) 7385 command 'set signcolumn=yes:2' 7386 feed 'gg' 7387 feed '2<C-e>' 7388 7389 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'X', end_row = 3 }) 7390 7391 screen:expect([[ 7392 {7:X }^l3 | 7393 {7:X }l4 | 7394 {7: }l5 | 7395 {7: } | 7396 {1:~ }|*5 7397 | 7398 ]]) 7399 end) 7400 7401 it('can add lots of signs', function() 7402 screen:try_resize(40, 10) 7403 command 'normal 10oa b c d e f g h' 7404 7405 for i = 1, 10 do 7406 api.nvim_buf_set_extmark(0, ns, i, 0, { end_col = 1, hl_group = 'Todo' }) 7407 api.nvim_buf_set_extmark(0, ns, i, 2, { end_col = 3, hl_group = 'Todo' }) 7408 api.nvim_buf_set_extmark(0, ns, i, 4, { end_col = 5, hl_group = 'Todo' }) 7409 api.nvim_buf_set_extmark(0, ns, i, 6, { end_col = 7, hl_group = 'Todo' }) 7410 api.nvim_buf_set_extmark(0, ns, i, 8, { end_col = 9, hl_group = 'Todo' }) 7411 api.nvim_buf_set_extmark(0, ns, i, 10, { end_col = 11, hl_group = 'Todo' }) 7412 api.nvim_buf_set_extmark(0, ns, i, 12, { end_col = 13, hl_group = 'Todo' }) 7413 api.nvim_buf_set_extmark(0, ns, i, 14, { end_col = 15, hl_group = 'Todo' }) 7414 api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'W' }) 7415 api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'X' }) 7416 api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'Y' }) 7417 api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'Z' }) 7418 end 7419 7420 screen:expect([[ 7421 {7:Z Y X W }{100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:h} |*8 7422 {7:Z Y X W }{100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:^h} | 7423 | 7424 ]]) 7425 end) 7426 7427 it('works with priority #19716', function() 7428 screen:try_resize(20, 3) 7429 insert(example_test3) 7430 feed 'gg' 7431 7432 command('sign define Oldsign text=O3') 7433 command([[exe 'sign place 42 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7434 7435 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4', priority = 100 }) 7436 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S2', priority = 5 }) 7437 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S5', priority = 200 }) 7438 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', priority = 1 }) 7439 7440 screen:expect([[ 7441 {7:S5S4O3S2S1}^l1 | 7442 {7: }l2 | 7443 | 7444 ]]) 7445 7446 -- Check truncation works too 7447 api.nvim_set_option_value('signcolumn', 'auto', {}) 7448 7449 screen:expect([[ 7450 {7:S5}^l1 | 7451 {7: }l2 | 7452 | 7453 ]]) 7454 end) 7455 7456 it('does not overflow with many old signs #23852', function() 7457 screen:try_resize(20, 3) 7458 7459 command('set signcolumn:auto:9') 7460 command('sign define Oldsign text=O3') 7461 command([[exe 'sign place 01 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7462 command([[exe 'sign place 02 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7463 command([[exe 'sign place 03 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7464 command([[exe 'sign place 04 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7465 command([[exe 'sign place 05 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7466 command([[exe 'sign place 06 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7467 command([[exe 'sign place 07 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7468 command([[exe 'sign place 08 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7469 command([[exe 'sign place 09 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]]) 7470 screen:expect([[ 7471 {7:O3O3O3O3O3O3O3O3O3}^ | 7472 {1:~ }| 7473 | 7474 ]]) 7475 7476 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', priority = 1 }) 7477 screen:expect_unchanged() 7478 7479 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S5', priority = 200 }) 7480 screen:expect([[ 7481 {7:S5O3O3O3O3O3O3O3O3}^ | 7482 {1:~ }| 7483 | 7484 ]]) 7485 7486 assert_alive() 7487 end) 7488 7489 it('does not set signcolumn for signs without text', function() 7490 screen:try_resize(20, 3) 7491 api.nvim_set_option_value('signcolumn', 'auto', {}) 7492 insert(example_test3) 7493 feed 'gg' 7494 api.nvim_buf_set_extmark(0, ns, 0, -1, { number_hl_group = 'Error' }) 7495 screen:expect { grid = [[ 7496 ^l1 | 7497 l2 | 7498 | 7499 ]] } 7500 end) 7501 7502 it('correct width when removing multiple signs from sentinel line', function() 7503 screen:try_resize(20, 4) 7504 insert(example_test3) 7505 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', end_row = 3 }) 7506 api.nvim_buf_set_extmark(0, ns, 1, -1, { invalidate = true, sign_text = 'S2' }) 7507 api.nvim_buf_set_extmark(0, ns, 1, -1, { invalidate = true, sign_text = 'S3' }) 7508 feed('2Gdd') 7509 7510 screen:expect([[ 7511 {7:S1}l1 | 7512 {7:S1}^l3 | 7513 {7:S1}l4 | 7514 | 7515 ]]) 7516 end) 7517 7518 it('correct width with multiple overlapping signs', function() 7519 screen:try_resize(20, 4) 7520 insert(example_test3) 7521 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' }) 7522 api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S2', end_row = 2 }) 7523 api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S3', end_row = 2 }) 7524 feed('gg') 7525 7526 local s1 = [[ 7527 {7:S2S1}^l1 | 7528 {7:S3S2}l2 | 7529 {7:S3S2}l3 | 7530 | 7531 ]] 7532 screen:expect(s1) 7533 -- Correct width when :move'ing a line with signs 7534 command('move2') 7535 screen:expect([[ 7536 {7:S3 }l2 | 7537 {7:S3S2S1}^l1 | 7538 {7: }l3 | 7539 | 7540 ]]) 7541 command('silent undo') 7542 screen:expect { grid = s1 } 7543 command('d') 7544 screen:expect([[ 7545 {7:S3S2S1}^l2 | 7546 {7:S3S2 }l3 | 7547 {7: }l4 | 7548 | 7549 ]]) 7550 command('d') 7551 screen:expect([[ 7552 {7:S3S2S1}^l3 | 7553 {7: }l4 | 7554 {7: }l5 | 7555 | 7556 ]]) 7557 end) 7558 7559 it('correct width when adding and removing multiple signs', function() 7560 screen:try_resize(20, 4) 7561 insert(example_test3) 7562 feed('gg') 7563 command([[ 7564 let ns = nvim_create_namespace('') 7565 call nvim_buf_set_extmark(0, ns, 0, 0, {'sign_text':'S1', 'end_row':3}) 7566 let s1 = nvim_buf_set_extmark(0, ns, 2, 0, {'sign_text':'S2', 'end_row':4}) 7567 let s2 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'}) 7568 let s3 = nvim_buf_set_extmark(0, ns, 6, 0, {'sign_text':'S3'}) 7569 let s4 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'}) 7570 let s5 = nvim_buf_set_extmark(0, ns, 6, 0, {'sign_text':'S3'}) 7571 redraw! 7572 call nvim_buf_del_extmark(0, ns, s2) 7573 call nvim_buf_del_extmark(0, ns, s3) 7574 call nvim_buf_del_extmark(0, ns, s4) 7575 call nvim_buf_del_extmark(0, ns, s5) 7576 redraw! 7577 call nvim_buf_del_extmark(0, ns, s1) 7578 ]]) 7579 screen:expect([[ 7580 {7:S1}^l1 | 7581 {7:S1}l2 | 7582 {7:S1}l3 | 7583 | 7584 ]]) 7585 end) 7586 7587 it('correct width when deleting lines', function() 7588 screen:try_resize(20, 4) 7589 insert(example_test3) 7590 feed('gg') 7591 command([[ 7592 let ns = nvim_create_namespace('') 7593 call nvim_buf_set_extmark(0, ns, 4, 0, {'sign_text':'S1'}) 7594 call nvim_buf_set_extmark(0, ns, 4, 0, {'sign_text':'S2'}) 7595 let s3 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'}) 7596 call nvim_buf_del_extmark(0, ns, s3) 7597 norm 4Gdd 7598 ]]) 7599 screen:expect([[ 7600 {7: }l3 | 7601 {7:S2S1}l5 | 7602 {7: }^ | 7603 | 7604 ]]) 7605 end) 7606 7607 it('correct width when splitting lines with signs on different columns', function() 7608 screen:try_resize(20, 4) 7609 insert(example_test3) 7610 feed('gg') 7611 api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' }) 7612 api.nvim_buf_set_extmark(0, ns, 0, 1, { sign_text = 'S2' }) 7613 feed('a<cr><esc>') 7614 screen:expect([[ 7615 {7:S1}l | 7616 {7:S2}^1 | 7617 {7: }l2 | 7618 | 7619 ]]) 7620 end) 7621 7622 it('correct width after wiping a buffer', function() 7623 screen:try_resize(20, 4) 7624 insert(example_test3) 7625 feed('gg') 7626 local buf = api.nvim_get_current_buf() 7627 api.nvim_buf_set_extmark(buf, ns, 0, 0, { sign_text = 'h' }) 7628 screen:expect([[ 7629 {7:h }^l1 | 7630 {7: }l2 | 7631 {7: }l3 | 7632 | 7633 ]]) 7634 api.nvim_win_set_buf(0, api.nvim_create_buf(false, true)) 7635 api.nvim_buf_delete(buf, { unload = true, force = true }) 7636 api.nvim_buf_set_lines(buf, 0, -1, false, { '' }) 7637 api.nvim_win_set_buf(0, buf) 7638 screen:expect { grid = [[ 7639 ^ | 7640 {1:~ }|*2 7641 | 7642 ]] } 7643 end) 7644 7645 it('correct width with moved marks before undo savepos', function() 7646 screen:try_resize(20, 4) 7647 insert(example_test3) 7648 feed('gg') 7649 exec_lua([[ 7650 local ns = vim.api.nvim_create_namespace('') 7651 vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' }) 7652 vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = 'S2' }) 7653 local s3 = vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S3' }) 7654 local s4 = vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S4' }) 7655 vim.schedule(function() 7656 vim.cmd('silent d3') 7657 vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { id = s3, sign_text = 'S3' }) 7658 vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { id = s4, sign_text = 'S4' }) 7659 vim.cmd('silent undo') 7660 vim.api.nvim_buf_del_extmark(0, ns, s3) 7661 end) 7662 ]]) 7663 7664 screen:expect([[ 7665 {7:S1}^l1 | 7666 {7:S2}l2 | 7667 {7:S4}l3 | 7668 | 7669 ]]) 7670 end) 7671 7672 it('no crash with sign after many marks #27137', function() 7673 screen:try_resize(20, 4) 7674 insert('a') 7675 for _ = 0, 104 do 7676 api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'Error', end_col = 1 }) 7677 end 7678 api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' }) 7679 7680 screen:expect([[ 7681 {7:S1}{9:^a} | 7682 {1:~ }|*2 7683 | 7684 ]]) 7685 end) 7686 7687 it('correct sort order with multiple namespaces and same id', function() 7688 local ns2 = api.nvim_create_namespace('') 7689 api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1', id = 1 }) 7690 api.nvim_buf_set_extmark(0, ns2, 0, 0, { sign_text = 'S2', id = 1 }) 7691 7692 screen:expect([[ 7693 {7:S2S1}^ | 7694 {1:~ }|*8 7695 | 7696 ]]) 7697 end) 7698 7699 it('correct number of signs after deleting text (#27046)', function() 7700 command('call setline(1, ["foo"]->repeat(31))') 7701 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 0, sign_text = 'S1' }) 7702 api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 0, end_col = 3, hl_group = 'Error' }) 7703 api.nvim_buf_set_extmark(0, ns, 9, 0, { end_row = 9, sign_text = 'S2' }) 7704 api.nvim_buf_set_extmark(0, ns, 9, 0, { end_row = 9, end_col = 3, hl_group = 'Error' }) 7705 api.nvim_buf_set_extmark(0, ns, 19, 0, { end_row = 19, sign_text = 'S3' }) 7706 api.nvim_buf_set_extmark(0, ns, 19, 0, { end_row = 19, end_col = 3, hl_group = 'Error' }) 7707 api.nvim_buf_set_extmark(0, ns, 29, 0, { end_row = 29, sign_text = 'S4' }) 7708 api.nvim_buf_set_extmark(0, ns, 29, 0, { end_row = 29, end_col = 3, hl_group = 'Error' }) 7709 api.nvim_buf_set_extmark(0, ns, 30, 0, { end_row = 30, sign_text = 'S5' }) 7710 api.nvim_buf_set_extmark(0, ns, 30, 0, { end_row = 30, end_col = 3, hl_group = 'Error' }) 7711 command('0d29') 7712 7713 screen:expect([[ 7714 {7:S4S3S2S1}{9:^foo} | 7715 {7:S5 }{9:foo} | 7716 {1:~ }|*7 7717 29 fewer lines | 7718 ]]) 7719 7720 api.nvim_buf_clear_namespace(0, ns, 0, -1) 7721 end) 7722 7723 it([[correct numberwidth with 'signcolumn' set to "number" #28984]], function() 7724 command('set number numberwidth=1 signcolumn=number') 7725 api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' }) 7726 screen:expect([[ 7727 {7:S1 }^ | 7728 {1:~ }|*8 7729 | 7730 ]]) 7731 api.nvim_buf_del_extmark(0, ns, 1) 7732 screen:expect([[ 7733 {8:1 }^ | 7734 {1:~ }|*8 7735 | 7736 ]]) 7737 end) 7738 7739 it('supports emoji as signs', function() 7740 insert(example_test3) 7741 feed 'gg' 7742 api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = '🧑🌾' }) 7743 -- VS16 can change width of character 7744 api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = '❤️' }) 7745 api.nvim_buf_set_extmark(0, ns, 3, 0, { sign_text = '❤' }) 7746 api.nvim_buf_set_extmark(0, ns, 4, 0, { sign_text = '❤x' }) 7747 screen:expect([[ 7748 {7: }^l1 | 7749 {7:🧑🌾}l2 | 7750 {7:❤️}l3 | 7751 {7:❤ }l4 | 7752 {7:❤x}l5 | 7753 {7: } | 7754 {1:~ }|*3 7755 | 7756 ]]) 7757 eq("Invalid 'sign_text'", pcall_err(api.nvim_buf_set_extmark, 0, ns, 5, 0, { sign_text = '❤️x' })) 7758 end) 7759 7760 it('auto signcolumn hides with invalidated sign', function() 7761 api.nvim_set_option_value('signcolumn', 'auto', {}) 7762 api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1', invalidate = true }) 7763 feed('ia<cr>b<esc>dd') 7764 screen:expect({ 7765 grid = [[ 7766 ^a | 7767 {1:~ }|*8 7768 | 7769 ]], 7770 }) 7771 end) 7772 7773 it('signcolumn correctly tracked with signs beyond eob and pair end before start', function() 7774 api.nvim_set_option_value('signcolumn', 'auto:2', {}) 7775 api.nvim_set_option_value('filetype', 'lua', {}) 7776 api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' }) 7777 api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S1' }) 7778 api.nvim_set_hl(0, 'SignColumn', { link = 'Error' }) 7779 screen:expect([[ 7780 ^foo | 7781 bar | 7782 {1:~ }|*7 7783 | 7784 ]]) 7785 api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S2', end_row = 1 }) 7786 api.nvim_buf_set_lines(0, 0, -1, false, { '-- foo', '-- bar' }) 7787 api.nvim_buf_clear_namespace(0, ns, 0, -1) 7788 screen:expect([[ 7789 ^-- foo | 7790 -- bar | 7791 {1:~ }|*7 7792 | 7793 ]]) 7794 assert_alive() 7795 end) 7796 end) 7797 7798 describe('decorations: virt_text', function() 7799 local ns, screen ---@type integer, test.functional.ui.screen 7800 7801 before_each(function() 7802 clear() 7803 screen = Screen.new(50, 10) 7804 ns = api.nvim_create_namespace('test') 7805 end) 7806 7807 it('avoids regression in #17638', function() 7808 command 'set number relativenumber' 7809 command 'normal 4ohello' 7810 command 'normal aVIRTUAL' 7811 7812 api.nvim_buf_set_extmark(0, ns, 2, 0, { 7813 virt_text = { { 'hello', 'String' } }, 7814 virt_text_win_col = 20, 7815 }) 7816 7817 screen:expect { 7818 grid = [[ 7819 {8: 4 } | 7820 {8: 3 }hello | 7821 {8: 2 }hello {26:hello} | 7822 {8: 1 }hello | 7823 {8:5 }helloVIRTUA^L | 7824 {1:~ }|*4 7825 | 7826 ]], 7827 } 7828 7829 -- Trigger a screen update 7830 feed('k') 7831 7832 screen:expect { 7833 grid = [[ 7834 {8: 3 } | 7835 {8: 2 }hello | 7836 {8: 1 }hello {26:hello} | 7837 {8:4 }hell^o | 7838 {8: 1 }helloVIRTUAL | 7839 {1:~ }|*4 7840 | 7841 ]], 7842 } 7843 end) 7844 7845 it('redraws correctly when re-using extmark ids', function() 7846 command 'normal 5ohello' 7847 7848 screen:expect { 7849 grid = [[ 7850 | 7851 hello |*4 7852 hell^o | 7853 {1:~ }|*3 7854 | 7855 ]], 7856 } 7857 7858 for row = 1, 5 do 7859 api.nvim_buf_set_extmark(0, ns, row, 0, { id = 1, virt_text = { { 'world', 'Normal' } } }) 7860 end 7861 7862 screen:expect { 7863 grid = [[ 7864 | 7865 hello |*4 7866 hell^o world | 7867 {1:~ }|*3 7868 | 7869 ]], 7870 } 7871 end) 7872 7873 it('redraws correctly when removing mark whose end ends up in front of start', function() 7874 command('normal 5ohello') 7875 api.nvim_buf_set_extmark(0, ns, 2, 0, { end_col = 1, virt_text = { { 'world', 'Normal' } } }) 7876 screen:expect([[ 7877 | 7878 hello | 7879 hello world | 7880 hello |*2 7881 hell^o | 7882 {1:~ }|*3 7883 | 7884 ]]) 7885 feed('3Gdd') 7886 api.nvim_buf_clear_namespace(0, ns, 0, -1) 7887 screen:expect([[ 7888 | 7889 hello | 7890 ^hello | 7891 hello |*2 7892 {1:~ }|*4 7893 | 7894 ]]) 7895 end) 7896 end) 7897 7898 describe('decorations: window scoped', function() 7899 local screen ---@type test.functional.ui.screen 7900 local ns ---@type integer 7901 local win_other ---@type integer 7902 7903 local url = 'https://example.com' 7904 before_each(function() 7905 clear() 7906 screen = Screen.new(20, 10) 7907 screen:add_extra_attr_ids { 7908 [100] = { special = Screen.colors.Red, undercurl = true }, 7909 [101] = { url = 'https://example.com' }, 7910 } 7911 7912 ns = api.nvim_create_namespace 'test' 7913 7914 insert('12345') 7915 7916 win_other = api.nvim_open_win(0, false, { 7917 col = 0, 7918 row = 0, 7919 width = 20, 7920 height = 10, 7921 relative = 'win', 7922 style = 'minimal', 7923 hide = true, 7924 }) 7925 end) 7926 7927 local noextmarks = { 7928 grid = [[ 7929 1234^5 | 7930 {1:~ }|*8 7931 | 7932 ]], 7933 } 7934 7935 local function set_extmark(line, col, opts) 7936 return api.nvim_buf_set_extmark(0, ns, line, col, opts) 7937 end 7938 7939 it('hl_group', function() 7940 set_extmark(0, 0, { 7941 hl_group = 'Comment', 7942 end_col = 3, 7943 }) 7944 7945 api.nvim__ns_set(ns, { wins = { 0 } }) 7946 7947 screen:expect { 7948 grid = [[ 7949 {18:123}4^5 | 7950 {1:~ }|*8 7951 | 7952 ]], 7953 } 7954 7955 command 'split' 7956 command 'only' 7957 7958 screen:expect(noextmarks) 7959 end) 7960 7961 it('virt_text', function() 7962 set_extmark(0, 0, { 7963 virt_text = { { 'a', 'Comment' } }, 7964 virt_text_pos = 'eol', 7965 }) 7966 set_extmark(0, 5, { 7967 virt_text = { { 'b', 'Comment' } }, 7968 virt_text_pos = 'inline', 7969 }) 7970 set_extmark(0, 1, { 7971 virt_text = { { 'c', 'Comment' } }, 7972 virt_text_pos = 'overlay', 7973 }) 7974 set_extmark(0, 1, { 7975 virt_text = { { 'd', 'Comment' } }, 7976 virt_text_pos = 'right_align', 7977 }) 7978 7979 api.nvim__ns_set(ns, { wins = { 0 } }) 7980 7981 screen:expect { 7982 grid = [[ 7983 1{18:c}34^5{18:b} {18:a} {18:d}| 7984 {1:~ }|*8 7985 | 7986 ]], 7987 } 7988 7989 command 'split' 7990 command 'only' 7991 7992 screen:expect(noextmarks) 7993 7994 api.nvim__ns_set(ns, { wins = {} }) 7995 7996 screen:expect { 7997 grid = [[ 7998 1{18:c}34^5{18:b} {18:a} {18:d}| 7999 {1:~ }|*8 8000 | 8001 ]], 8002 } 8003 end) 8004 8005 it('virt_lines', function() 8006 set_extmark(0, 0, { 8007 virt_lines = { { { 'a', 'Comment' } } }, 8008 }) 8009 8010 api.nvim__ns_set(ns, { wins = { 0 } }) 8011 8012 screen:expect { 8013 grid = [[ 8014 1234^5 | 8015 {18:a} | 8016 {1:~ }|*7 8017 | 8018 ]], 8019 } 8020 8021 command 'split' 8022 command 'only' 8023 8024 screen:expect(noextmarks) 8025 end) 8026 8027 it('redraws correctly with inline virt_text and wrapping', function() 8028 set_extmark(0, 2, { 8029 virt_text = { { ('b'):rep(18), 'Comment' } }, 8030 virt_text_pos = 'inline', 8031 }) 8032 8033 api.nvim__ns_set(ns, { wins = { 0 } }) 8034 8035 screen:expect { 8036 grid = [[ 8037 12{18:bbbbbbbbbbbbbbbbbb}| 8038 34^5 | 8039 {1:~ }|*7 8040 | 8041 ]], 8042 } 8043 8044 api.nvim__ns_set(ns, { wins = { win_other } }) 8045 8046 screen:expect(noextmarks) 8047 end) 8048 8049 pending('sign_text', function() 8050 -- TODO(altermo): The window signcolumn width is calculated wrongly (when `signcolumn=auto`) 8051 -- This happens in function `win_redraw_signcols` on line containing `buf_meta_total(buf, kMTMetaSignText) > 0` 8052 set_extmark(0, 0, { 8053 sign_text = 'a', 8054 sign_hl_group = 'Comment', 8055 }) 8056 8057 api.nvim__ns_set(ns, { wins = { 0 } }) 8058 8059 screen:expect { 8060 grid = [[ 8061 a 1234^5 | 8062 {2:~ }|*8 8063 | 8064 ]], 8065 } 8066 8067 command 'split' 8068 command 'only' 8069 8070 screen:expect(noextmarks) 8071 end) 8072 8073 it('statuscolumn hl group', function() 8074 set_extmark(0, 0, { 8075 number_hl_group = 'comment', 8076 }) 8077 set_extmark(0, 0, { 8078 line_hl_group = 'comment', 8079 }) 8080 8081 command 'set number' 8082 8083 api.nvim__ns_set(ns, { wins = { win_other } }) 8084 8085 screen:expect { 8086 grid = [[ 8087 {8: 1 }1234^5 | 8088 {1:~ }|*8 8089 | 8090 ]], 8091 } 8092 8093 api.nvim__ns_set(ns, { wins = { 0 } }) 8094 8095 screen:expect { 8096 grid = [[ 8097 {18: 1 1234^5 }| 8098 {1:~ }|*8 8099 | 8100 ]], 8101 } 8102 8103 command 'split' 8104 command 'only' 8105 8106 screen:expect { 8107 grid = [[ 8108 {8: 1 }1234^5 | 8109 {1:~ }|*8 8110 | 8111 ]], 8112 } 8113 end) 8114 8115 it('spell', function() 8116 api.nvim_buf_set_lines(0, 0, -1, true, { 'aa' }) 8117 8118 set_extmark(0, 0, { 8119 spell = true, 8120 end_col = 2, 8121 }) 8122 8123 command 'set spelloptions=noplainbuffer' 8124 command 'set spell' 8125 command 'syntax off' 8126 8127 screen:expect({ unchanged = true }) 8128 8129 api.nvim__ns_set(ns, { wins = { win_other } }) 8130 8131 screen:expect { 8132 grid = [[ 8133 a^a | 8134 {1:~ }|*8 8135 | 8136 ]], 8137 } 8138 8139 api.nvim__ns_set(ns, { wins = { 0 } }) 8140 8141 screen:expect { 8142 grid = [[ 8143 {100:a^a} | 8144 {1:~ }|*8 8145 | 8146 ]], 8147 } 8148 8149 command 'split' 8150 command 'only' 8151 8152 screen:expect { 8153 grid = [[ 8154 a^a | 8155 {1:~ }|*8 8156 | 8157 ]], 8158 } 8159 end) 8160 8161 it('url', function() 8162 set_extmark(0, 0, { 8163 end_col = 3, 8164 url = url, 8165 }) 8166 8167 api.nvim__ns_set(ns, { wins = { 0 } }) 8168 8169 screen:expect { 8170 grid = [[ 8171 {101:123}4^5 | 8172 {1:~ }|*8 8173 | 8174 ]], 8175 } 8176 8177 command 'split' 8178 command 'only' 8179 8180 screen:expect(noextmarks) 8181 end) 8182 8183 it('change namespace scope', function() 8184 set_extmark(0, 0, { 8185 hl_group = 'Comment', 8186 end_col = 3, 8187 }) 8188 8189 api.nvim__ns_set(ns, { wins = { 0 } }) 8190 eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) 8191 8192 screen:expect { 8193 grid = [[ 8194 {18:123}4^5 | 8195 {1:~ }|*8 8196 | 8197 ]], 8198 } 8199 8200 command 'split' 8201 command 'only' 8202 8203 screen:expect(noextmarks) 8204 8205 api.nvim__ns_set(ns, { wins = { 0 } }) 8206 eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) 8207 8208 screen:expect { 8209 grid = [[ 8210 {18:123}4^5 | 8211 {1:~ }|*8 8212 | 8213 ]], 8214 } 8215 8216 local win_new = api.nvim_open_win(0, false, { 8217 col = 0, 8218 row = 0, 8219 width = 20, 8220 height = 10, 8221 relative = 'win', 8222 style = 'minimal', 8223 hide = true, 8224 }) 8225 8226 api.nvim__ns_set(ns, { wins = { win_new } }) 8227 eq({ wins = { win_new } }, api.nvim__ns_get(ns)) 8228 8229 screen:expect(noextmarks) 8230 end) 8231 8232 it('namespace get works', function() 8233 eq({ wins = {} }, api.nvim__ns_get(ns)) 8234 8235 api.nvim__ns_set(ns, { wins = { 0 } }) 8236 8237 eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) 8238 8239 api.nvim__ns_set(ns, { wins = {} }) 8240 8241 eq({ wins = {} }, api.nvim__ns_get(ns)) 8242 end) 8243 8244 it('remove window from namespace scope when deleted', function() 8245 api.nvim__ns_set(ns, { wins = { 0 } }) 8246 8247 eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) 8248 8249 command 'split' 8250 command 'only' 8251 8252 eq({ wins = {} }, api.nvim__ns_get(ns)) 8253 end) 8254 end)