cmdline_spec.lua (47418B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 local Screen = require('test.functional.ui.screen') 4 5 local clear, feed = n.clear, n.feed 6 local source = n.source 7 local command = n.command 8 local assert_alive = n.assert_alive 9 local poke_eventloop = n.poke_eventloop 10 local exec = n.exec 11 local eval = n.eval 12 local eq = t.eq 13 local is_os = t.is_os 14 local api = n.api 15 16 local function test_cmdline(linegrid) 17 local screen 18 19 before_each(function() 20 clear() 21 screen = Screen.new(25, 5, { rgb = true, ext_cmdline = true, ext_linegrid = linegrid }) 22 end) 23 24 it('works', function() 25 feed(':') 26 screen:expect { 27 grid = [[ 28 ^ | 29 {1:~ }|*3 30 | 31 ]], 32 cmdline = { { firstc = ':', content = { { '' } }, pos = 0 } }, 33 } 34 35 feed('sign') 36 screen:expect { 37 grid = [[ 38 ^ | 39 {1:~ }|*3 40 | 41 ]], 42 cmdline = { { firstc = ':', content = { { 'sign' } }, pos = 4 } }, 43 } 44 45 feed('<Left>') 46 screen:expect { 47 grid = [[ 48 ^ | 49 {1:~ }|*3 50 | 51 ]], 52 cmdline = { { firstc = ':', content = { { 'sign' } }, pos = 3 } }, 53 } 54 55 feed('<bs>') 56 screen:expect { 57 grid = [[ 58 ^ | 59 {1:~ }|*3 60 | 61 ]], 62 cmdline = { { firstc = ':', content = { { 'sin' } }, pos = 2 } }, 63 } 64 65 feed('<Esc>') 66 screen:expect { 67 grid = [[ 68 ^ | 69 {1:~ }|*3 70 | 71 ]], 72 cmdline = { { abort = true } }, 73 } 74 end) 75 76 it('works with input()', function() 77 feed(':call input("input", "default")<cr>') 78 screen:expect({ 79 grid = [[ 80 ^ | 81 {1:~ }|*3 82 | 83 ]], 84 cmdline = { { content = { { 'default' } }, pos = 7, prompt = 'input' } }, 85 }) 86 87 feed('<cr>') 88 screen:expect_unchanged() 89 end) 90 91 it('works with special chars and nested cmdline', function() 92 feed(':xx<c-r>') 93 screen:expect { 94 grid = [[ 95 ^ | 96 {1:~ }|*3 97 | 98 ]], 99 cmdline = { { firstc = ':', content = { { 'xx' } }, pos = 2, special = { '"', true } } }, 100 } 101 102 feed('=') 103 screen:expect { 104 grid = [[ 105 ^ | 106 {1:~ }|*3 107 | 108 ]], 109 cmdline = { 110 { firstc = ':', content = { { 'xx' } }, pos = 2, special = { '"', true } }, 111 { firstc = '=', content = { { '' } }, pos = 0 }, 112 }, 113 } 114 115 feed('1+2') 116 117 screen:expect { 118 grid = [[ 119 ^ | 120 {1:~ }|*3 121 | 122 ]], 123 cmdline = { 124 { firstc = ':', content = { { 'xx' } }, pos = 2, special = { '"', true } }, 125 { 126 firstc = '=', 127 content = { 128 { '1', 26, linegrid and 'NvimNumber' or nil }, 129 { '+', 15, linegrid and 'NvimBinaryPlus' or nil }, 130 { '2', 26, linegrid and 'NvimNumber' or nil }, 131 }, 132 pos = 3, 133 }, 134 }, 135 } 136 137 -- erase information, so we check if it is retransmitted 138 command('mode') 139 screen:expect { 140 grid = [[ 141 ^ | 142 {1:~ }|*3 143 | 144 ]], 145 cmdline = { 146 { firstc = ':', content = { { 'xx' } }, pos = 2, special = { '"', true } }, 147 { 148 firstc = '=', 149 content = { 150 { '1', 26, linegrid and 'NvimNumber' or nil }, 151 { '+', 15, linegrid and 'NvimBinaryPlus' or nil }, 152 { '2', 26, linegrid and 'NvimNumber' or nil }, 153 }, 154 pos = 3, 155 }, 156 }, 157 reset = true, 158 } 159 160 feed('<cr>') 161 screen:expect { 162 grid = [[ 163 ^ | 164 {1:~ }|*3 165 | 166 ]], 167 cmdline = { { firstc = ':', content = { { 'xx3' } }, pos = 3 } }, 168 } 169 170 feed('<esc>') 171 screen:expect { 172 grid = [[ 173 ^ | 174 {1:~ }|*3 175 | 176 ]], 177 cmdline = { { abort = true } }, 178 } 179 end) 180 181 it('works with function definitions', function() 182 feed(':function Foo()<cr>') 183 screen:expect { 184 grid = [[ 185 ^ | 186 {1:~ }|*3 187 | 188 ]], 189 cmdline = { { indent = 2, firstc = ':', content = { { '' } }, pos = 0 } }, 190 cmdline_block = { { { 'function Foo()' } } }, 191 } 192 193 feed('line1<cr>') 194 screen:expect { 195 grid = [[ 196 ^ | 197 {1:~ }|*3 198 | 199 ]], 200 cmdline = { { indent = 2, firstc = ':', content = { { '' } }, pos = 0 } }, 201 cmdline_block = { { { 'function Foo()' } }, { { ' line1' } } }, 202 } 203 204 command('mode') 205 screen:expect { 206 grid = [[ 207 ^ | 208 {1:~ }|*3 209 | 210 ]], 211 cmdline = { { indent = 2, firstc = ':', content = { { '' } }, pos = 0 } }, 212 cmdline_block = { { { 'function Foo()' } }, { { ' line1' } } }, 213 reset = true, 214 } 215 216 feed('endfunction<cr>') 217 screen:expect([[ 218 ^ | 219 {1:~ }|*3 220 | 221 ]]) 222 223 -- Try once more, to check buffer is reinitialized. #8007 224 feed(':function Bar()<cr>') 225 screen:expect { 226 grid = [[ 227 ^ | 228 {1:~ }|*3 229 | 230 ]], 231 cmdline = { { indent = 2, firstc = ':', content = { { '' } }, pos = 0 } }, 232 cmdline_block = { { { 'function Bar()' } } }, 233 } 234 235 feed('endfunction<cr>') 236 screen:expect([[ 237 ^ | 238 {1:~ }|*3 239 | 240 ]]) 241 end) 242 243 it('works with cmdline window', function() 244 feed(':make') 245 screen:expect { 246 grid = [[ 247 ^ | 248 {1:~ }|*3 249 | 250 ]], 251 cmdline = { { firstc = ':', content = { { 'make' } }, pos = 4 } }, 252 } 253 254 feed('<c-f>') 255 screen:expect([[ 256 | 257 {2:[No Name] }| 258 {1::}make^ | 259 {3:[Command Line] }| 260 | 261 ]]) 262 263 -- nested cmdline 264 feed(':yank') 265 screen:expect { 266 grid = [[ 267 | 268 {2:[No Name] }| 269 {1::}make^ | 270 {3:[Command Line] }| 271 | 272 ]], 273 cmdline = { 274 nil, 275 { firstc = ':', content = { { 'yank' } }, pos = 4 }, 276 }, 277 } 278 279 command('mode') 280 screen:expect { 281 grid = [[ 282 | 283 {2:[No Name] }| 284 {1::}make^ | 285 {3:[Command Line] }| 286 | 287 ]], 288 cmdline = { 289 nil, 290 { firstc = ':', content = { { 'yank' } }, pos = 4 }, 291 }, 292 reset = true, 293 } 294 295 feed('<c-c>') 296 screen:expect { 297 grid = [[ 298 | 299 {2:[No Name] }| 300 {1::}make^ | 301 {3:[Command Line] }| 302 | 303 ]], 304 cmdline = { [2] = { abort = true } }, 305 } 306 307 feed('<c-c>') 308 screen:expect { 309 grid = [[ 310 ^ | 311 {2:[No Name] }| 312 {1::}make | 313 {3:[Command Line] }| 314 | 315 ]], 316 cmdline = { { firstc = ':', content = { { 'make' } }, pos = 4 } }, 317 } 318 319 command('redraw!') 320 screen:expect { 321 grid = [[ 322 ^ | 323 {1:~ }|*3 324 | 325 ]], 326 cmdline = { { firstc = ':', content = { { 'make' } }, pos = 4 } }, 327 } 328 end) 329 330 it('works with inputsecret()', function() 331 feed(":call inputsecret('secret:')<cr>abc123") 332 screen:expect { 333 grid = [[ 334 ^ | 335 {1:~ }|*3 336 | 337 ]], 338 cmdline = { { prompt = 'secret:', content = { { '******' } }, pos = 6 } }, 339 } 340 end) 341 342 it('works with highlighted cmdline', function() 343 source([[ 344 highlight RBP1 guibg=Red 345 highlight RBP2 guibg=Yellow 346 highlight RBP3 guibg=Green 347 highlight RBP4 guibg=Blue 348 let g:NUM_LVLS = 4 349 function RainBowParens(cmdline) 350 let ret = [] 351 let i = 0 352 let lvl = 0 353 while i < len(a:cmdline) 354 if a:cmdline[i] is# '(' 355 call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) 356 let lvl += 1 357 elseif a:cmdline[i] is# ')' 358 let lvl -= 1 359 call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) 360 endif 361 let i += 1 362 endwhile 363 return ret 364 endfunction 365 map <f5> :let x = input({'prompt':'>','highlight':'RainBowParens'})<cr> 366 "map <f5> :let x = input({'prompt':'>'})<cr> 367 ]]) 368 feed('<f5>(a(b)a)') 369 screen:expect { 370 grid = [[ 371 ^ | 372 {1:~ }|*3 373 | 374 ]], 375 cmdline = { 376 { 377 prompt = '>', 378 content = { 379 { '(', 30, linegrid and 'RBP1' or nil }, 380 { 'a' }, 381 { '(', 10, linegrid and 'RBP2' or nil }, 382 { 'b' }, 383 { ')', 10, linegrid and 'RBP2' or nil }, 384 { 'a' }, 385 { ')', 30, linegrid and 'RBP1' or nil }, 386 }, 387 pos = 7, 388 }, 389 }, 390 } 391 end) 392 393 it('works together with ext_wildmenu', function() 394 command('set wildmode=full') 395 command('set wildmenu') 396 screen:set_option('ext_wildmenu', true) 397 feed(':sign <tab>') 398 399 screen:expect { 400 grid = [[ 401 ^ | 402 {1:~ }|*3 403 | 404 ]], 405 cmdline = { { firstc = ':', content = { { 'sign define' } }, pos = 11 } }, 406 wildmenu_items = { 'define', 'jump', 'list', 'place', 'undefine', 'unplace' }, 407 wildmenu_pos = 0, 408 } 409 410 feed('<tab>') 411 screen:expect { 412 grid = [[ 413 ^ | 414 {1:~ }|*3 415 | 416 ]], 417 cmdline = { { firstc = ':', content = { { 'sign jump' } }, pos = 9 } }, 418 wildmenu_items = { 'define', 'jump', 'list', 'place', 'undefine', 'unplace' }, 419 wildmenu_pos = 1, 420 } 421 422 feed('<left><left>') 423 screen:expect { 424 grid = [[ 425 ^ | 426 {1:~ }|*3 427 | 428 ]], 429 cmdline = { { firstc = ':', content = { { 'sign ' } }, pos = 5 } }, 430 wildmenu_items = { 'define', 'jump', 'list', 'place', 'undefine', 'unplace' }, 431 wildmenu_pos = -1, 432 } 433 434 feed('<right>') 435 screen:expect { 436 grid = [[ 437 ^ | 438 {1:~ }|*3 439 | 440 ]], 441 cmdline = { { firstc = ':', content = { { 'sign define' } }, pos = 11 } }, 442 wildmenu_items = { 'define', 'jump', 'list', 'place', 'undefine', 'unplace' }, 443 wildmenu_pos = 0, 444 } 445 446 feed('a') 447 screen:expect { 448 grid = [[ 449 ^ | 450 {1:~ }|*3 451 | 452 ]], 453 cmdline = { { firstc = ':', content = { { 'sign definea' } }, pos = 12 } }, 454 } 455 end) 456 457 local function test_ext_cmdline_popupmenu() 458 local expected = { 459 { 'define', '', '', '' }, 460 { 'jump', '', '', '' }, 461 { 'list', '', '', '' }, 462 { 'place', '', '', '' }, 463 { 'undefine', '', '', '' }, 464 { 'unplace', '', '', '' }, 465 } 466 467 command('set wildmode=full') 468 command('set wildmenu') 469 screen:set_option('ext_popupmenu', true) 470 feed(':sign <tab>') 471 472 screen:expect { 473 grid = [[ 474 ^ | 475 {1:~ }|*3 476 | 477 ]], 478 cmdline = { { firstc = ':', content = { { 'sign define' } }, pos = 11 } }, 479 popupmenu = { items = expected, pos = 0, anchor = { -1, 0, 5 } }, 480 } 481 482 feed('<tab>') 483 screen:expect { 484 grid = [[ 485 ^ | 486 {1:~ }|*3 487 | 488 ]], 489 cmdline = { { firstc = ':', content = { { 'sign jump' } }, pos = 9 } }, 490 popupmenu = { items = expected, pos = 1, anchor = { -1, 0, 5 } }, 491 } 492 493 feed('<left><left>') 494 screen:expect { 495 grid = [[ 496 ^ | 497 {1:~ }|*3 498 | 499 ]], 500 cmdline = { { firstc = ':', content = { { 'sign ' } }, pos = 5 } }, 501 popupmenu = { items = expected, pos = -1, anchor = { -1, 0, 5 } }, 502 } 503 504 feed('<right>') 505 screen:expect { 506 grid = [[ 507 ^ | 508 {1:~ }|*3 509 | 510 ]], 511 cmdline = { { firstc = ':', content = { { 'sign define' } }, pos = 11 } }, 512 popupmenu = { items = expected, pos = 0, anchor = { -1, 0, 5 } }, 513 } 514 515 feed('a') 516 screen:expect { 517 grid = [[ 518 ^ | 519 {1:~ }|*3 520 | 521 ]], 522 cmdline = { { firstc = ':', content = { { 'sign definea' } }, pos = 12 } }, 523 } 524 feed('<esc>') 525 526 -- check positioning with multibyte char in pattern 527 command('e långfile1') 528 command('sp långfile2') 529 feed(':b lå<tab>') 530 screen:expect { 531 grid = [[ 532 ^ | 533 {3:långfile2 }| 534 | 535 {2:långfile1 }| 536 | 537 ]], 538 cmdline = { { content = { { 'b långfile1' } }, firstc = ':', pos = 12 } }, 539 popupmenu = { 540 anchor = { -1, 0, 2 }, 541 items = { { 'långfile1', '', '', '' }, { 'långfile2', '', '', '' } }, 542 pos = 0, 543 }, 544 } 545 546 feed('<Esc>') 547 command('silent %bwipe') 548 549 command('set shellslash') 550 -- position is correct when expanding environment variable #20348 551 command('silent cd test/functional/fixtures') 552 n.fn.setenv('XNDIR', 'wildpum/Xnamedir') 553 feed(':e $XNDIR/<Tab>') 554 screen:expect { 555 grid = [[ 556 ^ | 557 {1:~ }|*3 558 | 559 ]], 560 cmdline = { { content = { { 'e wildpum/Xnamedir/XdirA/' } }, firstc = ':', pos = 25 } }, 561 popupmenu = { 562 anchor = { -1, 0, 19 }, 563 items = { { 'XdirA/', '', '', '' }, { 'XfileA', '', '', '' } }, 564 pos = 0, 565 }, 566 } 567 568 feed('<Esc>') 569 command('set wildmode=longest,full') 570 feed(':sign u<tab>') 571 screen:expect { 572 grid = [[ 573 ^ | 574 {1:~ }|*3 575 | 576 ]], 577 cmdline = { { content = { { 'sign un' } }, firstc = ':', pos = 7 } }, 578 } 579 580 feed('<tab>') 581 local s_undefine_unplace_0 = { 582 grid = [[ 583 ^ | 584 {1:~ }|*3 585 | 586 ]], 587 cmdline = { { content = { { 'sign undefine' } }, firstc = ':', pos = 13 } }, 588 popupmenu = { 589 anchor = { -1, 0, 5 }, 590 items = { { 'undefine', '', '', '' }, { 'unplace', '', '', '' } }, 591 pos = 0, 592 }, 593 } 594 screen:expect(s_undefine_unplace_0) 595 596 feed('<Esc>') 597 screen:expect([[ 598 ^ | 599 {1:~ }|*3 600 | 601 ]]) 602 603 feed(':sign un<tab>') 604 screen:expect(s_undefine_unplace_0) 605 end 606 607 describe('works together with ext_popupmenu', function() 608 it('with wildoptions=pum', function() 609 command('set wildoptions=pum') 610 test_ext_cmdline_popupmenu() 611 end) 612 613 it('with wildoptions=', function() 614 command('set wildoptions=') 615 test_ext_cmdline_popupmenu() 616 end) 617 end) 618 619 it('ext_wildmenu takes precedence over ext_popupmenu', function() 620 local expected = { 621 'define', 622 'jump', 623 'list', 624 'place', 625 'undefine', 626 'unplace', 627 } 628 629 command('set wildmode=full') 630 command('set wildmenu') 631 screen:set_option('ext_wildmenu', true) 632 screen:set_option('ext_popupmenu', true) 633 feed(':sign <tab>') 634 635 screen:expect { 636 grid = [[ 637 ^ | 638 {1:~ }|*3 639 | 640 ]], 641 cmdline = { { firstc = ':', content = { { 'sign define' } }, pos = 11 } }, 642 wildmenu_items = expected, 643 wildmenu_pos = 0, 644 } 645 end) 646 647 it("doesn't send invalid events when aborting mapping #10000", function() 648 command('set notimeout') 649 command('cnoremap ab c') 650 651 feed(':xa') 652 screen:expect { 653 grid = [[ 654 ^ | 655 {1:~ }|*3 656 | 657 ]], 658 cmdline = { { content = { { 'x' } }, firstc = ':', pos = 1, special = { 'a', false } } }, 659 } 660 661 -- This used to send an invalid event where pos where larger than the total 662 -- length of content. Checked in _handle_cmdline_show. 663 feed('<esc>') 664 screen:expect({ 665 grid = [[ 666 ^ | 667 {1:~ }|*3 668 | 669 ]], 670 cmdline = { { abort = true } }, 671 }) 672 end) 673 674 it('does not move cursor to curwin #20309', function() 675 local win = api.nvim_get_current_win() 676 command('norm icmdlinewin') 677 command('new') 678 command('norm icurwin') 679 feed(':') 680 api.nvim_win_set_cursor(win, { 1, 7 }) 681 api.nvim__redraw({ win = win, cursor = true }) 682 screen:expect { 683 grid = [[ 684 curwin | 685 {3:[No Name] [+] }| 686 cmdline^win | 687 {2:[No Name] [+] }| 688 | 689 ]], 690 cmdline = { { content = { { '' } }, firstc = ':', pos = 0 } }, 691 } 692 end) 693 694 it('show prompt hl_id', function() 695 screen:expect([[ 696 ^ | 697 {1:~ }|*3 698 | 699 ]]) 700 feed(':echohl Error | call input("Prompt:")<CR>') 701 screen:expect({ 702 grid = [[ 703 ^ | 704 {1:~ }|*3 705 | 706 ]], 707 cmdline = { { content = { { '' } }, hl = 'Error', pos = 0, prompt = 'Prompt:' } }, 708 }) 709 end) 710 711 it('works with conditionals', function() 712 screen:expect([[ 713 ^ | 714 {1:~ }|*3 715 | 716 ]]) 717 feed(':if 1<CR>') 718 screen:expect({ 719 grid = [[ 720 ^ | 721 {1:~ }|*3 722 | 723 ]], 724 cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, 725 cmdline_block = { { { 'if 1' } } }, 726 }) 727 feed('let x = 1<CR>') 728 screen:expect({ 729 grid = [[ 730 ^ | 731 {1:~ }|*3 732 | 733 ]], 734 cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, 735 cmdline_block = { { { 'if 1' } }, { { ' let x = 1' } } }, 736 }) 737 feed('<CR>') 738 eq('let x = 1', eval('@:')) 739 screen:expect({ 740 grid = [[ 741 ^ | 742 {1:~ }|*3 743 | 744 ]], 745 cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, 746 cmdline_block = { { { 'if 1' } }, { { ' let x = 1' } }, { { ' ' } } }, 747 }) 748 feed('call input("foo:")<CR>') 749 screen:expect({ 750 grid = [[ 751 ^ | 752 {1:~ }|*3 753 | 754 ]], 755 cmdline = { { content = { { '' } }, pos = 0, prompt = 'foo:' } }, 756 cmdline_block = { 757 { { 'if 1' } }, 758 { { ' let x = 1' } }, 759 { { ' ' } }, 760 { { ' call input("foo:")' } }, 761 }, 762 }) 763 feed('bar<CR>') 764 screen:expect({ 765 grid = [[ 766 ^ | 767 {1:~ }|*3 768 | 769 ]], 770 cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, 771 cmdline_block = { 772 { { 'if 1' } }, 773 { { ' let x = 1' } }, 774 { { ' ' } }, 775 { { ' call input("foo:")' } }, 776 }, 777 }) 778 feed('endif') 779 screen:expect({ 780 grid = [[ 781 ^ | 782 {1:~ }|*3 783 | 784 ]], 785 cmdline = { { content = { { 'endif' } }, firstc = ':', indent = 2, pos = 5 } }, 786 cmdline_block = { 787 { { 'if 1' } }, 788 { { ' let x = 1' } }, 789 { { ' ' } }, 790 { { ' call input("foo:")' } }, 791 }, 792 }) 793 feed('<CR>') 794 screen:expect([[ 795 ^ | 796 {1:~ }|*3 797 | 798 ]]) 799 end) 800 801 it('works with exmode', function() 802 feed('gQ') 803 screen:expect({ 804 grid = [[ 805 | 806 {3: }| 807 Entering Ex mode. Type "| 808 visual" to go to Normal m| 809 ode.^ | 810 ]], 811 cmdline = { { content = { { '' } }, firstc = ':', pos = 0 } }, 812 }) 813 feed('echo "foo"<CR>') 814 screen:expect({ 815 grid = [[ 816 {3: }| 817 Entering Ex mode. Type "| 818 visual" to go to Normal m| 819 ode. | 820 foo^ | 821 ]], 822 cmdline = { { content = { { '' } }, firstc = ':', pos = 0 } }, 823 cmdline_block = { { { 'echo "foo"' } } }, 824 }) 825 feed('vis<CR>') 826 screen:expect([[ 827 ^ | 828 {1:~ }|*3 829 | 830 ]]) 831 end) 832 end 833 834 -- the representation of cmdline and cmdline_block contents changed with ext_linegrid 835 -- (which uses indexed highlights) so make sure to test both 836 describe('ui/ext_cmdline', function() 837 test_cmdline(true) 838 end) 839 describe('ui/ext_cmdline (legacy highlights)', function() 840 test_cmdline(false) 841 end) 842 843 describe('cmdline redraw', function() 844 local screen 845 before_each(function() 846 clear() 847 screen = Screen.new(25, 5, { rgb = true }) 848 end) 849 850 it('with timer', function() 851 feed(':012345678901234567890123456789') 852 screen:expect([[ 853 | 854 {1:~ }| 855 {3: }| 856 :012345678901234567890123| 857 456789^ | 858 ]]) 859 command('call timer_start(0, {-> 1})') 860 screen:expect_unchanged() 861 end) 862 863 it('with <Cmd>', function() 864 if is_os('bsd') then 865 pending('FIXME #10804') 866 end 867 command('cmap a <Cmd>call sin(0)<CR>') -- no-op 868 feed(':012345678901234567890123456789') 869 screen:expect([[ 870 | 871 {1:~ }| 872 {3: }| 873 :012345678901234567890123| 874 456789^ | 875 ]]) 876 feed('a') 877 screen:expect_unchanged() 878 end) 879 880 it('after pressing Ctrl-C in cmdwin in Visual mode #18967', function() 881 screen:try_resize(40, 10) 882 command('set cmdwinheight=3') 883 feed('q:iabc<Esc>vhh') 884 screen:expect([[ 885 | 886 {1:~ }|*3 887 {2:[No Name] }| 888 {1::}^a{17:bc} | 889 {1:~ }|*2 890 {3:[Command Line] }| 891 {5:-- VISUAL --} | 892 ]]) 893 feed('<C-C>') 894 screen:expect([[ 895 | 896 {1:~ }|*3 897 {2:[No Name] }| 898 {1::}a{17:bc} | 899 {1:~ }|*2 900 {3:[Command Line] }| 901 :^abc | 902 ]]) 903 end) 904 905 it('with rightleftcmd', function() 906 command('set rightleft rightleftcmd=search shortmess+=s') 907 api.nvim_buf_set_lines(0, 0, -1, true, { "let's rock!" }) 908 screen:expect([[ 909 !kcor s'te^l| 910 {1: ~}|*3 911 | 912 ]]) 913 914 feed '/' 915 screen:expect([[ 916 !kcor s'tel| 917 {1: ~}|*3 918 ^ /| 919 ]]) 920 921 feed "let's" 922 -- note: cursor looks off but looks alright in real use 923 -- when rendered as a block so it touches the end of the text 924 screen:expect([[ 925 !kcor {2:s'tel}| 926 {1: ~}|*3 927 ^ s'tel/| 928 ]]) 929 930 -- cursor movement 931 feed '<space>' 932 screen:expect([[ 933 !kcor{2: s'tel}| 934 {1: ~}|*3 935 ^ s'tel/| 936 ]]) 937 938 feed 'rock' 939 screen:expect([[ 940 !{2:kcor s'tel}| 941 {1: ~}|*3 942 ^ kcor s'tel/| 943 ]]) 944 945 feed '<right>' 946 screen:expect([[ 947 !{2:kcor s'tel}| 948 {1: ~}|*3 949 ^kcor s'tel/| 950 ]]) 951 952 feed '<left>' 953 screen:expect([[ 954 !{2:kcor s'tel}| 955 {1: ~}|*3 956 ^ kcor s'tel/| 957 ]]) 958 959 feed '<cr>' 960 screen:expect([[ 961 !{10:kcor s'te^l}| 962 {1: ~}|*3 963 kcor s'tel/ | 964 ]]) 965 end) 966 967 it('prompt with silent mapping and screen update', function() 968 command([[nmap <silent> T :call confirm("Save changes?", "&Yes\n&No\n&Cancel")<CR>]]) 969 feed('T') 970 screen:expect([[ 971 | 972 {3: }| 973 | 974 {6:Save changes?} | 975 {6:[Y]es, (N)o, (C)ancel: }^ | 976 ]]) 977 command('call setline(1, "foo") | redraw') 978 screen:expect([[ 979 foo | 980 {3: }| 981 | 982 {6:Save changes?} | 983 {6:[Y]es, (N)o, (C)ancel: }^ | 984 ]]) 985 feed('Y') 986 screen:expect([[ 987 ^foo | 988 {1:~ }|*3 989 | 990 ]]) 991 screen:try_resize(75, screen._height) 992 feed(':call inputlist(["foo", "bar"])<CR>') 993 screen:expect([[ 994 foo | 995 {3: }| 996 foo | 997 bar | 998 Type number and <Enter> or click with the mouse (q or empty cancels): ^ | 999 ]]) 1000 command('redraw') 1001 screen:expect_unchanged() 1002 1003 command('set keymap=dvorak') 1004 feed('<C-^>') 1005 command('redraw') 1006 screen:expect_unchanged() 1007 1008 feed('<C-^>') 1009 command('set keymap&') 1010 command('redraw') 1011 screen:expect_unchanged() 1012 end) 1013 1014 it('substitute confirm prompt does not scroll', function() 1015 screen:try_resize(75, screen._height) 1016 command('call setline(1, "foo")') 1017 command('set report=0') 1018 feed(':%s/foo/bar/c<CR>') 1019 screen:expect([[ 1020 {2:foo} | 1021 {1:~ }|*3 1022 {6:replace with bar? (y)es/(n)o/(a)ll/(q)uit/(l)ast/scroll up(^E)/down(^Y)}^ | 1023 ]]) 1024 feed('y') 1025 screen:expect([[ 1026 ^bar | 1027 {1:~ }|*3 1028 1 substitution on 1 line | 1029 ]]) 1030 end) 1031 end) 1032 1033 describe('statusline is redrawn on entering cmdline', function() 1034 local screen 1035 1036 before_each(function() 1037 clear() 1038 screen = Screen.new(25, 5) 1039 command('set laststatus=2') 1040 end) 1041 1042 it('from normal mode', function() 1043 command('set statusline=%{mode()}') 1044 screen:expect([[ 1045 ^ | 1046 {1:~ }|*2 1047 {3:n }| 1048 | 1049 ]]) 1050 1051 feed(':') 1052 screen:expect([[ 1053 | 1054 {1:~ }|*2 1055 {3:c }| 1056 :^ | 1057 ]]) 1058 end) 1059 1060 it('from normal mode when : is mapped', function() 1061 command('set statusline=%{mode()}') 1062 command('nnoremap ; :') 1063 1064 screen:expect([[ 1065 ^ | 1066 {1:~ }|*2 1067 {3:n }| 1068 | 1069 ]]) 1070 1071 feed(';') 1072 screen:expect([[ 1073 | 1074 {1:~ }|*2 1075 {3:c }| 1076 :^ | 1077 ]]) 1078 end) 1079 1080 it('with scrolled messages', function() 1081 screen:try_resize(35, 14) 1082 exec([[ 1083 let g:count = 0 1084 autocmd CmdlineEnter * let g:count += 1 1085 split 1086 resize 1 1087 setlocal statusline=%{mode()}%{g:count} 1088 setlocal winbar=%{mode()}%{g:count} 1089 ]]) 1090 feed(':echoerr doesnotexist<cr>') 1091 screen:expect([[ 1092 {5:c1 }| 1093 | 1094 {3:c1 }| 1095 | 1096 {1:~ }|*5 1097 {3: }| 1098 {9:E121: Undefined variable: doesnotex}| 1099 {9:ist} | 1100 {6:Press ENTER or type command to cont}| 1101 {6:inue}^ | 1102 ]]) 1103 feed(':echoerr doesnotexist<cr>') 1104 screen:expect([[ 1105 {5:c2 }| 1106 | 1107 {3:c2 }| 1108 | 1109 {1:~ }|*2 1110 {3: }| 1111 {9:E121: Undefined variable: doesnotex}| 1112 {9:ist} | 1113 {6:Press ENTER or type command to cont}| 1114 {9:E121: Undefined variable: doesnotex}| 1115 {9:ist} | 1116 {6:Press ENTER or type command to cont}| 1117 {6:inue}^ | 1118 ]]) 1119 1120 feed(':echoerr doesnotexist<cr>') 1121 screen:expect([[ 1122 {5:c3 }| 1123 | 1124 {3:c3 }| 1125 {3: }| 1126 {9:E121: Undefined variable: doesnotex}| 1127 {9:ist} | 1128 {6:Press ENTER or type command to cont}| 1129 {9:E121: Undefined variable: doesnotex}| 1130 {9:ist} | 1131 {6:Press ENTER or type command to cont}| 1132 {9:E121: Undefined variable: doesnotex}| 1133 {9:ist} | 1134 {6:Press ENTER or type command to cont}| 1135 {6:inue}^ | 1136 ]]) 1137 1138 feed('<cr>') 1139 screen:expect([[ 1140 {5:n3 }| 1141 ^ | 1142 {3:n3 }| 1143 | 1144 {1:~ }|*8 1145 {2:[No Name] }| 1146 | 1147 ]]) 1148 end) 1149 1150 describe('if custom statusline is set by', function() 1151 before_each(function() 1152 command('set statusline=') 1153 screen:expect([[ 1154 ^ | 1155 {1:~ }|*2 1156 {3:[No Name] }| 1157 | 1158 ]]) 1159 end) 1160 1161 it('CmdlineEnter autocommand', function() 1162 command('autocmd CmdlineEnter * set statusline=command') 1163 feed(':') 1164 screen:expect([[ 1165 | 1166 {1:~ }|*2 1167 {3:command }| 1168 :^ | 1169 ]]) 1170 end) 1171 1172 it('ModeChanged autocommand', function() 1173 command('autocmd ModeChanged *:c set statusline=command') 1174 feed(':') 1175 screen:expect([[ 1176 | 1177 {1:~ }|*2 1178 {3:command }| 1179 :^ | 1180 ]]) 1181 end) 1182 end) 1183 end) 1184 1185 it('tabline is not redrawn in Ex mode #24122', function() 1186 clear() 1187 local screen = Screen.new(60, 5) 1188 1189 exec([[ 1190 set showtabline=2 1191 set tabline=%!MyTabLine() 1192 1193 function! MyTabLine() 1194 1195 return "foo" 1196 endfunction 1197 ]]) 1198 1199 feed('gQ') 1200 screen:expect([[ 1201 {2:foo }| 1202 | 1203 {3: }| 1204 Entering Ex mode. Type "visual" to go to Normal mode. | 1205 :^ | 1206 ]]) 1207 1208 feed('echo 1<CR>') 1209 screen:expect([[ 1210 {3: }| 1211 Entering Ex mode. Type "visual" to go to Normal mode. | 1212 :echo 1 | 1213 1 | 1214 :^ | 1215 ]]) 1216 end) 1217 1218 describe('cmdline height', function() 1219 before_each(clear) 1220 1221 it('does not crash resized screen #14263', function() 1222 local screen = Screen.new(25, 10) 1223 command('set cmdheight=9999') 1224 screen:try_resize(25, 5) 1225 assert_alive() 1226 end) 1227 1228 it('unchanged when restoring window sizes with global statusline', function() 1229 command('set cmdheight=2 laststatus=2') 1230 feed('q:') 1231 command('set cmdheight=1 laststatus=3 | quit') 1232 -- Available lines changed, so closing cmdwin should skip restoring window sizes, leaving the 1233 -- cmdheight unchanged. 1234 eq(1, eval('&cmdheight')) 1235 end) 1236 1237 it('not increased to 0 from 1 with wincmd _', function() 1238 command('set cmdheight=0 laststatus=0') 1239 command('wincmd _') 1240 eq(0, eval('&cmdheight')) 1241 end) 1242 end) 1243 1244 describe('cmdheight=0', function() 1245 local screen 1246 before_each(function() 1247 clear() 1248 screen = Screen.new(25, 5) 1249 end) 1250 1251 it('with redrawdebug=invalid resize -1', function() 1252 command('set redrawdebug=invalid cmdheight=0 noruler laststatus=0') 1253 screen:expect([[ 1254 ^ | 1255 {1:~ }|*4 1256 ]]) 1257 feed(':resize -1<CR>') 1258 screen:expect([[ 1259 ^ | 1260 {1:~ }|*3 1261 | 1262 ]]) 1263 assert_alive() 1264 end) 1265 1266 it('with cmdheight=1 noruler laststatus=2', function() 1267 command('set cmdheight=1 noruler laststatus=2') 1268 screen:expect([[ 1269 ^ | 1270 {1:~ }|*2 1271 {3:[No Name] }| 1272 | 1273 ]]) 1274 end) 1275 1276 it('with cmdheight=0 noruler laststatus=2', function() 1277 command('set cmdheight=0 noruler laststatus=2') 1278 screen:expect([[ 1279 ^ | 1280 {1:~ }|*3 1281 {3:[No Name] }| 1282 ]]) 1283 end) 1284 1285 it('with cmdheight=0 ruler laststatus=0', function() 1286 command('set cmdheight=0 ruler laststatus=0') 1287 screen:expect([[ 1288 ^ | 1289 {1:~ }|*4 1290 ]]) 1291 end) 1292 1293 it('with cmdheight=0 ruler laststatus=0', function() 1294 command('set cmdheight=0 noruler laststatus=0 showmode') 1295 feed('i') 1296 screen:expect { 1297 grid = [[ 1298 ^ | 1299 {1:~ }|*4 1300 ]], 1301 showmode = {}, 1302 } 1303 feed('<Esc>') 1304 eq(0, eval('&cmdheight')) 1305 end) 1306 1307 it('with cmdheight=0 ruler rulerformat laststatus=0', function() 1308 command('set cmdheight=0 noruler laststatus=0 rulerformat=%l,%c%= showmode') 1309 feed('i') 1310 screen:expect { 1311 grid = [[ 1312 ^ | 1313 {1:~ }|*4 1314 ]], 1315 showmode = {}, 1316 } 1317 feed('<Esc>') 1318 eq(0, eval('&cmdheight')) 1319 end) 1320 1321 it('with showmode', function() 1322 command('set cmdheight=1 noruler laststatus=0 showmode') 1323 feed('i') 1324 screen:expect([[ 1325 ^ | 1326 {1:~ }|*3 1327 {5:-- INSERT --} | 1328 ]]) 1329 feed('<Esc>') 1330 eq(1, eval('&cmdheight')) 1331 end) 1332 1333 it('when using command line', function() 1334 command('set cmdheight=0 noruler laststatus=0') 1335 feed(':') 1336 screen:expect([[ 1337 | 1338 {1:~ }|*3 1339 :^ | 1340 ]]) 1341 eq(0, eval('&cmdheight')) 1342 feed('<cr>') 1343 screen:expect { 1344 grid = [[ 1345 ^ | 1346 {1:~ }|*4 1347 ]], 1348 showmode = {}, 1349 } 1350 eq(0, eval('&cmdheight')) 1351 end) 1352 1353 it('when using input()', function() 1354 command('set cmdheight=0 noruler laststatus=0') 1355 feed(':call input("foo >")<cr>') 1356 screen:expect([[ 1357 | 1358 {1:~ }| 1359 {3: }| 1360 :call input("foo >") | 1361 foo >^ | 1362 ]]) 1363 eq(0, eval('&cmdheight')) 1364 feed('<cr>') 1365 screen:expect { 1366 grid = [[ 1367 ^ | 1368 {1:~ }|*4 1369 ]], 1370 showmode = {}, 1371 } 1372 eq(0, eval('&cmdheight')) 1373 end) 1374 1375 it('with winbar and splits', function() 1376 command('set cmdheight=0 noruler laststatus=3 winbar=foo') 1377 feed(':split<CR>') 1378 screen:expect([[ 1379 {3: }| 1380 :split | 1381 {9:E36: Not enough room} | 1382 {6:Press ENTER or type comma}| 1383 {6:nd to continue}^ | 1384 ]]) 1385 feed('<CR>') 1386 screen:expect([[ 1387 {5:foo }| 1388 ^ | 1389 {1:~ }|*2 1390 {3:[No Name] }| 1391 ]]) 1392 feed(':') 1393 screen:expect([[ 1394 {5:foo }| 1395 | 1396 {1:~ }|*2 1397 :^ | 1398 ]]) 1399 feed('<Esc>') 1400 screen:expect { 1401 grid = [[ 1402 {5:foo }| 1403 ^ | 1404 {1:~ }|*2 1405 {3:[No Name] }| 1406 ]], 1407 showmode = {}, 1408 } 1409 eq(0, eval('&cmdheight')) 1410 1411 assert_alive() 1412 end) 1413 1414 it('when macro with lastline', function() 1415 command('set cmdheight=0 display=lastline') 1416 feed('qq') 1417 screen:expect([[ 1418 ^ | 1419 {1:~ }|*4 1420 ]]) 1421 feed('q') 1422 screen:expect { 1423 grid = [[ 1424 ^ | 1425 {1:~ }|*4 1426 ]], 1427 unchanged = true, 1428 } 1429 end) 1430 1431 it('when substitute text', function() 1432 command('set cmdheight=0 noruler laststatus=3') 1433 feed('ifoo<ESC>') 1434 screen:try_resize(screen._width, 7) 1435 screen:expect([[ 1436 fo^o | 1437 {1:~ }|*5 1438 {3:[No Name] [+] }| 1439 ]]) 1440 1441 feed(':%s/foo/bar/gc<CR>') 1442 screen:expect([[ 1443 {2:foo} | 1444 {3: }| 1445 |*2 1446 {6:replace with bar? (y)es/(}| 1447 {6:n)o/(a)ll/(q)uit/(l)ast/s}| 1448 {6:croll up(^E)/down(^Y)}^ | 1449 ]]) 1450 1451 feed('y') 1452 screen:expect([[ 1453 ^bar | 1454 {1:~ }|*5 1455 {3:[No Name] [+] }| 1456 ]]) 1457 1458 assert_alive() 1459 end) 1460 1461 it('when window resize', function() 1462 command('set cmdheight=0') 1463 feed('<C-w>+') 1464 eq(0, eval('&cmdheight')) 1465 end) 1466 1467 it('with non-silent mappings with cmdline', function() 1468 command('set cmdheight=0') 1469 command('map <f3> :nohlsearch<cr>') 1470 feed('iaabbaa<esc>/aa<cr>') 1471 screen:expect([[ 1472 {10:^aa}bb{10:aa} | 1473 {1:~ }|*4 1474 ]]) 1475 1476 feed('<f3>') 1477 screen:expect([[ 1478 ^aabbaa | 1479 {1:~ }|*4 1480 ]]) 1481 end) 1482 1483 it('with silent! at startup', function() 1484 clear { args = { '-c', 'set cmdheight=0', '-c', 'autocmd VimEnter * silent! call Foo()' } } 1485 screen = Screen.new(25, 5) 1486 -- doesn't crash while not displaying silent! error message 1487 screen:expect([[ 1488 ^ | 1489 {1:~ }|*4 1490 ]]) 1491 end) 1492 1493 it('with multigrid', function() 1494 clear { args = { '--cmd', 'set cmdheight=0' } } 1495 screen = Screen.new(25, 5, { ext_multigrid = true }) 1496 api.nvim_buf_set_lines(0, 0, -1, true, { 'p' }) 1497 screen:expect { 1498 grid = [[ 1499 ## grid 1 1500 [2:-------------------------]|*5 1501 ## grid 2 1502 ^p | 1503 {1:~ }|*4 1504 ## grid 3 1505 ]], 1506 win_viewport = { 1507 [2] = { 1508 win = 1000, 1509 topline = 0, 1510 botline = 2, 1511 curline = 0, 1512 curcol = 0, 1513 linecount = 1, 1514 sum_scroll_delta = 0, 1515 }, 1516 }, 1517 } 1518 1519 feed '/p' 1520 screen:expect { 1521 grid = [[ 1522 ## grid 1 1523 [2:-------------------------]|*4 1524 [3:-------------------------]| 1525 ## grid 2 1526 {2:p} | 1527 {1:~ }|*4 1528 ## grid 3 1529 /p^ | 1530 ]], 1531 win_viewport = { 1532 [2] = { 1533 win = 1000, 1534 topline = 0, 1535 botline = 2, 1536 curline = 0, 1537 curcol = 1, 1538 linecount = 1, 1539 sum_scroll_delta = 0, 1540 }, 1541 }, 1542 } 1543 end) 1544 1545 it('winbar is redrawn on entering cmdline and :redrawstatus #20336', function() 1546 exec([[ 1547 set cmdheight=0 1548 set winbar=%{mode()}%=:%{getcmdline()} 1549 ]]) 1550 feed(':') 1551 screen:expect([[ 1552 {5:c :}| 1553 | 1554 {1:~ }|*2 1555 :^ | 1556 ]]) 1557 feed('echo') 1558 -- not redrawn yet 1559 screen:expect([[ 1560 {5:c :}| 1561 | 1562 {1:~ }|*2 1563 :echo^ | 1564 ]]) 1565 command('redrawstatus') 1566 screen:expect([[ 1567 {5:c :echo}| 1568 | 1569 {1:~ }|*2 1570 :echo^ | 1571 ]]) 1572 end) 1573 1574 it('window equalization with laststatus=0 #20367', function() 1575 screen:try_resize(60, 9) 1576 command('set cmdheight=0 laststatus=0') 1577 command('vsplit') 1578 screen:expect([[ 1579 ^ │ | 1580 {1:~ }│{1:~ }|*8 1581 ]]) 1582 feed(':') 1583 command('split') 1584 feed('<Esc>') 1585 screen:expect([[ 1586 ^ │ | 1587 {1:~ }│{1:~ }|*3 1588 {3:[No Name] }│{1:~ }| 1589 │{1:~ }| 1590 {1:~ }│{1:~ }|*3 1591 ]]) 1592 command('resize 2') 1593 screen:expect([[ 1594 ^ │ | 1595 {1:~ }│{1:~ }| 1596 {3:[No Name] }│{1:~ }| 1597 │{1:~ }| 1598 {1:~ }│{1:~ }|*5 1599 ]]) 1600 feed(':') 1601 command('wincmd =') 1602 feed('<Esc>') 1603 screen:expect([[ 1604 ^ │ | 1605 {1:~ }│{1:~ }|*3 1606 {3:[No Name] }│{1:~ }| 1607 │{1:~ }| 1608 {1:~ }│{1:~ }|*3 1609 ]]) 1610 end) 1611 1612 it('no assert failure with showcmd', function() 1613 command('set showcmd cmdheight=0') 1614 feed('d') 1615 screen:expect([[ 1616 ^ | 1617 {1:~ }|*4 1618 ]]) 1619 assert_alive() 1620 end) 1621 1622 it('can only be resized to 0 if set explicitly', function() 1623 command('set laststatus=2') 1624 command('resize +1') 1625 screen:expect([[ 1626 ^ | 1627 {1:~ }|*2 1628 {3:[No Name] }| 1629 | 1630 ]]) 1631 command('set cmdheight=0') 1632 screen:expect([[ 1633 ^ | 1634 {1:~ }|*3 1635 {3:[No Name] }| 1636 ]]) 1637 command('resize -1') 1638 screen:expect([[ 1639 ^ | 1640 {1:~ }|*2 1641 {3:[No Name] }| 1642 | 1643 ]]) 1644 command('resize +1') 1645 screen:expect([[ 1646 ^ | 1647 {1:~ }|*3 1648 {3:[No Name] }| 1649 ]]) 1650 end) 1651 1652 it('can be resized with external messages', function() 1653 clear() 1654 screen = Screen.new(25, 5, { rgb = true, ext_messages = true }) 1655 command('set laststatus=2 mouse=a') 1656 command('resize -1') 1657 screen:expect([[ 1658 ^ | 1659 {1:~ }|*2 1660 {3:[No Name] }| 1661 | 1662 ]]) 1663 api.nvim_input_mouse('left', 'press', '', 0, 3, 10) 1664 poke_eventloop() 1665 api.nvim_input_mouse('left', 'drag', '', 0, 4, 10) 1666 screen:expect([[ 1667 ^ | 1668 {1:~ }|*3 1669 {3:[No Name] }| 1670 ]]) 1671 end) 1672 end)