1" Tests for the terminal window. 2 3source check.vim 4CheckFeature terminal 5 6source shared.vim 7source screendump.vim 8 9let s:python = PythonProg() 10let $PROMPT_COMMAND='' 11 12" Open a terminal with a shell, assign the job to g:job and return the buffer 13" number. 14func Run_shell_in_terminal(options) 15 if has('win32') 16 let buf = term_start([&shell,'/k'], a:options) 17 else 18 let buf = term_start(&shell, a:options) 19 endif 20 21 let termlist = term_list() 22 call assert_equal(1, len(termlist)) 23 call assert_equal(buf, termlist[0]) 24 25 let g:job = term_getjob(buf) 26 call assert_equal(v:t_job, type(g:job)) 27 28 let string = string({'job': buf->term_getjob()}) 29 call assert_match("{'job': 'process \\d\\+ run'}", string) 30 31 return buf 32endfunc 33 34func Test_terminal_basic() 35 au TerminalOpen * let b:done = 'yes' 36 let buf = Run_shell_in_terminal({}) 37 38 if has("unix") 39 call assert_match('^/dev/', job_info(g:job).tty_out) 40 call assert_match('^/dev/', term_gettty('')) 41 else 42 " ConPTY works on anonymous pipe. 43 if !has('conpty') 44 call assert_match('^\\\\.\\pipe\\', job_info(g:job).tty_out) 45 call assert_match('^\\\\.\\pipe\\', ''->term_gettty()) 46 endif 47 endif 48 call assert_equal('t', mode()) 49 call assert_equal('yes', b:done) 50 call assert_match('%aR[^\n]*running]', execute('ls')) 51 call assert_match('%aR[^\n]*running]', execute('ls R')) 52 call assert_notmatch('%[^\n]*running]', execute('ls F')) 53 call assert_notmatch('%[^\n]*running]', execute('ls ?')) 54 55 call StopShellInTerminal(buf) 56 call term_wait(buf) 57 call assert_equal('n', mode()) 58 call assert_match('%aF[^\n]*finished]', execute('ls')) 59 call assert_match('%aF[^\n]*finished]', execute('ls F')) 60 call assert_notmatch('%[^\n]*finished]', execute('ls R')) 61 call assert_notmatch('%[^\n]*finished]', execute('ls ?')) 62 63 " closing window wipes out the terminal buffer a with finished job 64 close 65 call assert_equal("", bufname(buf)) 66 67 au! TerminalOpen 68 unlet g:job 69endfunc 70 71func Test_terminal_TerminalWinOpen() 72 au TerminalWinOpen * let b:done = 'yes' 73 let buf = Run_shell_in_terminal({}) 74 call assert_equal('yes', b:done) 75 call StopShellInTerminal(buf) 76 " closing window wipes out the terminal buffer with the finished job 77 close 78 79 if has("unix") 80 terminal ++hidden ++open sleep 1 81 sleep 1 82 call assert_fails("echo b:done", 'E121:') 83 endif 84 85 au! TerminalWinOpen 86endfunc 87 88func Test_terminal_make_change() 89 let buf = Run_shell_in_terminal({}) 90 call StopShellInTerminal(buf) 91 call term_wait(buf) 92 93 setlocal modifiable 94 exe "normal Axxx\<Esc>" 95 call assert_fails(buf . 'bwipe', 'E517') 96 undo 97 98 exe buf . 'bwipe' 99 unlet g:job 100endfunc 101 102func Test_terminal_paste_register() 103 let @" = "text to paste" 104 105 let buf = Run_shell_in_terminal({}) 106 " Wait for the shell to display a prompt 107 call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) 108 109 call feedkeys("echo \<C-W>\"\" \<C-W>\"=37 + 5\<CR>\<CR>", 'xt') 110 call WaitForAssert({-> assert_match("echo text to paste 42$", getline(1))}) 111 call WaitForAssert({-> assert_equal('text to paste 42', 2->getline())}) 112 113 exe buf . 'bwipe!' 114 unlet g:job 115endfunc 116 117func Test_terminal_wipe_buffer() 118 let buf = Run_shell_in_terminal({}) 119 call assert_fails(buf . 'bwipe', 'E517') 120 exe buf . 'bwipe!' 121 call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) 122 call assert_equal("", bufname(buf)) 123 124 unlet g:job 125endfunc 126 127func Test_terminal_split_quit() 128 let buf = Run_shell_in_terminal({}) 129 call term_wait(buf) 130 split 131 quit! 132 call term_wait(buf) 133 sleep 50m 134 call assert_equal('run', job_status(g:job)) 135 136 quit! 137 call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) 138 139 exe buf . 'bwipe' 140 unlet g:job 141endfunc 142 143func Test_terminal_hide_buffer() 144 let buf = Run_shell_in_terminal({}) 145 setlocal bufhidden=hide 146 quit 147 for nr in range(1, winnr('$')) 148 call assert_notequal(winbufnr(nr), buf) 149 endfor 150 call assert_true(bufloaded(buf)) 151 call assert_true(buflisted(buf)) 152 153 exe 'split ' . buf . 'buf' 154 call StopShellInTerminal(buf) 155 exe buf . 'bwipe' 156 157 unlet g:job 158endfunc 159 160func s:Nasty_exit_cb(job, st) 161 exe g:buf . 'bwipe!' 162 let g:buf = 0 163endfunc 164 165func Get_cat_123_cmd() 166 if has('win32') 167 if !has('conpty') 168 return 'cmd /c "cls && color 2 && echo 123"' 169 else 170 " When clearing twice, extra sequence is not output. 171 return 'cmd /c "cls && cls && color 2 && echo 123"' 172 endif 173 else 174 call writefile(["\<Esc>[32m123"], 'Xtext') 175 return "cat Xtext" 176 endif 177endfunc 178 179func Test_terminal_nasty_cb() 180 let cmd = Get_cat_123_cmd() 181 let g:buf = term_start(cmd, {'exit_cb': function('s:Nasty_exit_cb')}) 182 let g:job = term_getjob(g:buf) 183 184 call WaitForAssert({-> assert_equal("dead", job_status(g:job))}) 185 call WaitForAssert({-> assert_equal(0, g:buf)}) 186 unlet g:job 187 unlet g:buf 188 call delete('Xtext') 189endfunc 190 191func Check_123(buf) 192 let l = term_scrape(a:buf, 0) 193 call assert_true(len(l) == 0) 194 let l = term_scrape(a:buf, 999) 195 call assert_true(len(l) == 0) 196 let l = a:buf->term_scrape(1) 197 call assert_true(len(l) > 0) 198 call assert_equal('1', l[0].chars) 199 call assert_equal('2', l[1].chars) 200 call assert_equal('3', l[2].chars) 201 call assert_equal('#00e000', l[0].fg) 202 call assert_equal(0, term_getattr(l[0].attr, 'bold')) 203 call assert_equal(0, l[0].attr->term_getattr('italic')) 204 if has('win32') 205 " On Windows 'background' always defaults to dark, even though the terminal 206 " may use a light background. Therefore accept both white and black. 207 call assert_match('#ffffff\|#000000', l[0].bg) 208 else 209 if &background == 'light' 210 call assert_equal('#ffffff', l[0].bg) 211 else 212 call assert_equal('#000000', l[0].bg) 213 endif 214 endif 215 216 let l = term_getline(a:buf, -1) 217 call assert_equal('', l) 218 let l = term_getline(a:buf, 0) 219 call assert_equal('', l) 220 let l = term_getline(a:buf, 999) 221 call assert_equal('', l) 222 let l = term_getline(a:buf, 1) 223 call assert_equal('123', l) 224endfunc 225 226func Test_terminal_scrape_123() 227 let cmd = Get_cat_123_cmd() 228 let buf = term_start(cmd) 229 230 let termlist = term_list() 231 call assert_equal(1, len(termlist)) 232 call assert_equal(buf, termlist[0]) 233 234 " Nothing happens with invalid buffer number 235 call term_wait(1234) 236 237 call term_wait(buf) 238 " On MS-Windows we first get a startup message of two lines, wait for the 239 " "cls" to happen, after that we have one line with three characters. 240 call WaitForAssert({-> assert_equal(3, len(term_scrape(buf, 1)))}) 241 call Check_123(buf) 242 243 " Must still work after the job ended. 244 let job = term_getjob(buf) 245 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 246 call term_wait(buf) 247 call Check_123(buf) 248 249 exe buf . 'bwipe' 250 call delete('Xtext') 251endfunc 252 253func Test_terminal_scrape_multibyte() 254 call writefile(["léttまrs"], 'Xtext') 255 if has('win32') 256 " Run cmd with UTF-8 codepage to make the type command print the expected 257 " multibyte characters. 258 let buf = term_start("cmd /K chcp 65001") 259 call term_sendkeys(buf, "type Xtext\<CR>") 260 eval buf->term_sendkeys("exit\<CR>") 261 let line = 4 262 else 263 let buf = term_start("cat Xtext") 264 let line = 1 265 endif 266 267 call WaitFor({-> len(term_scrape(buf, line)) >= 7 && term_scrape(buf, line)[0].chars == "l"}) 268 let l = term_scrape(buf, line) 269 call assert_true(len(l) >= 7) 270 call assert_equal('l', l[0].chars) 271 call assert_equal('é', l[1].chars) 272 call assert_equal(1, l[1].width) 273 call assert_equal('t', l[2].chars) 274 call assert_equal('t', l[3].chars) 275 call assert_equal('ま', l[4].chars) 276 call assert_equal(2, l[4].width) 277 call assert_equal('r', l[5].chars) 278 call assert_equal('s', l[6].chars) 279 280 let job = term_getjob(buf) 281 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 282 call term_wait(buf) 283 284 exe buf . 'bwipe' 285 call delete('Xtext') 286endfunc 287 288func Test_terminal_scroll() 289 call writefile(range(1, 200), 'Xtext') 290 if has('win32') 291 let cmd = 'cmd /c "type Xtext"' 292 else 293 let cmd = "cat Xtext" 294 endif 295 let buf = term_start(cmd) 296 297 let job = term_getjob(buf) 298 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 299 call term_wait(buf) 300 if has('win32') 301 " TODO: this should not be needed 302 sleep 100m 303 endif 304 305 let scrolled = buf->term_getscrolled() 306 call assert_equal(scrolled, term_getscrolled(buf)) 307 call assert_equal('1', getline(1)) 308 call assert_equal('1', term_getline(buf, 1 - scrolled)) 309 call assert_equal('49', getline(49)) 310 call assert_equal('49', term_getline(buf, 49 - scrolled)) 311 call assert_equal('200', getline(200)) 312 call assert_equal('200', term_getline(buf, 200 - scrolled)) 313 314 exe buf . 'bwipe' 315 call delete('Xtext') 316endfunc 317 318func Test_terminal_scrollback() 319 let buf = Run_shell_in_terminal({'term_rows': 15}) 320 set termwinscroll=100 321 call writefile(range(150), 'Xtext') 322 if has('win32') 323 call term_sendkeys(buf, "type Xtext\<CR>") 324 else 325 call term_sendkeys(buf, "cat Xtext\<CR>") 326 endif 327 let rows = term_getsize(buf)[0] 328 " On MS-Windows there is an empty line, check both last line and above it. 329 call WaitForAssert({-> assert_match( '149', term_getline(buf, rows - 1) . term_getline(buf, rows - 2))}) 330 let lines = line('$') 331 call assert_inrange(91, 100, lines) 332 333 call StopShellInTerminal(buf) 334 call term_wait(buf) 335 exe buf . 'bwipe' 336 set termwinscroll& 337 call delete('Xtext') 338endfunc 339 340func Test_terminal_postponed_scrollback() 341 " tail -f only works on Unix 342 CheckUnix 343 344 call writefile(range(50), 'Xtext') 345 call writefile([ 346 \ 'set shell=/bin/sh noruler', 347 \ 'terminal', 348 \ 'sleep 200m', 349 \ 'call feedkeys("tail -n 100 -f Xtext\<CR>", "xt")', 350 \ 'sleep 100m', 351 \ 'call feedkeys("\<C-W>N", "xt")', 352 \ ], 'XTest_postponed') 353 let buf = RunVimInTerminal('-S XTest_postponed', {}) 354 " Check that the Xtext lines are displayed and in Terminal-Normal mode 355 call VerifyScreenDump(buf, 'Test_terminal_01', {}) 356 357 silent !echo 'one more line' >>Xtext 358 " Screen will not change, move cursor to get a different dump 359 call term_sendkeys(buf, "k") 360 call VerifyScreenDump(buf, 'Test_terminal_02', {}) 361 362 " Back to Terminal-Job mode, text will scroll and show the extra line. 363 call term_sendkeys(buf, "a") 364 call VerifyScreenDump(buf, 'Test_terminal_03', {}) 365 366 call term_wait(buf) 367 call term_sendkeys(buf, "\<C-C>") 368 call term_wait(buf) 369 call term_sendkeys(buf, "exit\<CR>") 370 call term_wait(buf) 371 call term_sendkeys(buf, ":q\<CR>") 372 call StopVimInTerminal(buf) 373 call delete('XTest_postponed') 374 call delete('Xtext') 375endfunc 376 377" Run diff on two dumps with different size. 378func Test_terminal_dumpdiff_size() 379 call assert_equal(1, winnr('$')) 380 call term_dumpdiff('dumps/Test_incsearch_search_01.dump', 'dumps/Test_popup_command_01.dump') 381 call assert_equal(2, winnr('$')) 382 call assert_match('Test_incsearch_search_01.dump', getline(10)) 383 call assert_match(' +++++$', getline(11)) 384 call assert_match('Test_popup_command_01.dump', getline(31)) 385 call assert_equal(repeat('+', 75), getline(30)) 386 quit 387endfunc 388 389func Test_terminal_size() 390 let cmd = Get_cat_123_cmd() 391 392 exe 'terminal ++rows=5 ' . cmd 393 let size = term_getsize('') 394 bwipe! 395 call assert_equal(5, size[0]) 396 397 call term_start(cmd, {'term_rows': 6}) 398 let size = term_getsize('') 399 bwipe! 400 call assert_equal(6, size[0]) 401 402 vsplit 403 exe 'terminal ++rows=5 ++cols=33 ' . cmd 404 call assert_equal([5, 33], ''->term_getsize()) 405 406 call term_setsize('', 6, 0) 407 call assert_equal([6, 33], term_getsize('')) 408 409 eval ''->term_setsize(0, 35) 410 call assert_equal([6, 35], term_getsize('')) 411 412 call term_setsize('', 7, 30) 413 call assert_equal([7, 30], term_getsize('')) 414 415 bwipe! 416 call assert_fails("call term_setsize('', 7, 30)", "E955:") 417 418 call term_start(cmd, {'term_rows': 6, 'term_cols': 36}) 419 let size = term_getsize('') 420 bwipe! 421 call assert_equal([6, 36], size) 422 423 exe 'vertical terminal ++cols=20 ' . cmd 424 let size = term_getsize('') 425 bwipe! 426 call assert_equal(20, size[1]) 427 428 eval cmd->term_start({'vertical': 1, 'term_cols': 26}) 429 let size = term_getsize('') 430 bwipe! 431 call assert_equal(26, size[1]) 432 433 split 434 exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd 435 let size = term_getsize('') 436 bwipe! 437 call assert_equal([6, 20], size) 438 439 call term_start(cmd, {'vertical': 1, 'term_rows': 7, 'term_cols': 27}) 440 let size = term_getsize('') 441 bwipe! 442 call assert_equal([7, 27], size) 443 444 call delete('Xtext') 445endfunc 446 447func Test_terminal_curwin() 448 let cmd = Get_cat_123_cmd() 449 call assert_equal(1, winnr('$')) 450 451 split dummy 452 exe 'terminal ++curwin ' . cmd 453 call assert_equal(2, winnr('$')) 454 bwipe! 455 456 split dummy 457 call term_start(cmd, {'curwin': 1}) 458 call assert_equal(2, winnr('$')) 459 bwipe! 460 461 split dummy 462 call setline(1, 'change') 463 call assert_fails('terminal ++curwin ' . cmd, 'E37:') 464 call assert_equal(2, winnr('$')) 465 exe 'terminal! ++curwin ' . cmd 466 call assert_equal(2, winnr('$')) 467 bwipe! 468 469 split dummy 470 call setline(1, 'change') 471 call assert_fails("call term_start(cmd, {'curwin': 1})", 'E37:') 472 call assert_equal(2, winnr('$')) 473 bwipe! 474 475 split dummy 476 bwipe! 477 call delete('Xtext') 478endfunc 479 480func s:get_sleep_cmd() 481 if s:python != '' 482 let cmd = s:python . " test_short_sleep.py" 483 " 500 was not enough for Travis 484 let waittime = 900 485 else 486 echo 'This will take five seconds...' 487 let waittime = 2000 488 if has('win32') 489 let cmd = $windir . '\system32\timeout.exe 1' 490 else 491 let cmd = 'sleep 1' 492 endif 493 endif 494 return [cmd, waittime] 495endfunc 496 497func Test_terminal_finish_open_close() 498 call assert_equal(1, winnr('$')) 499 500 let [cmd, waittime] = s:get_sleep_cmd() 501 502 " shell terminal closes automatically 503 terminal 504 let buf = bufnr('%') 505 call assert_equal(2, winnr('$')) 506 " Wait for the shell to display a prompt 507 call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) 508 call StopShellInTerminal(buf) 509 call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime) 510 511 " shell terminal that does not close automatically 512 terminal ++noclose 513 let buf = bufnr('%') 514 call assert_equal(2, winnr('$')) 515 " Wait for the shell to display a prompt 516 call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) 517 call StopShellInTerminal(buf) 518 call assert_equal(2, winnr('$')) 519 quit 520 call assert_equal(1, winnr('$')) 521 522 exe 'terminal ++close ' . cmd 523 call assert_equal(2, winnr('$')) 524 wincmd p 525 call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime) 526 527 call term_start(cmd, {'term_finish': 'close'}) 528 call assert_equal(2, winnr('$')) 529 wincmd p 530 call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime) 531 call assert_equal(1, winnr('$')) 532 533 exe 'terminal ++open ' . cmd 534 close! 535 call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) 536 bwipe 537 538 call term_start(cmd, {'term_finish': 'open'}) 539 close! 540 call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) 541 bwipe 542 543 exe 'terminal ++hidden ++open ' . cmd 544 call assert_equal(1, winnr('$')) 545 call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) 546 bwipe 547 548 call term_start(cmd, {'term_finish': 'open', 'hidden': 1}) 549 call assert_equal(1, winnr('$')) 550 call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) 551 bwipe 552 553 call assert_fails("call term_start(cmd, {'term_opencmd': 'open'})", 'E475:') 554 call assert_fails("call term_start(cmd, {'term_opencmd': 'split %x'})", 'E475:') 555 call assert_fails("call term_start(cmd, {'term_opencmd': 'split %d and %s'})", 'E475:') 556 call assert_fails("call term_start(cmd, {'term_opencmd': 'split % and %d'})", 'E475:') 557 558 call term_start(cmd, {'term_finish': 'open', 'term_opencmd': '4split | buffer %d'}) 559 close! 560 call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) 561 call assert_equal(4, winheight(0)) 562 bwipe 563endfunc 564 565func Test_terminal_cwd() 566 if has('win32') 567 let cmd = 'cmd /c cd' 568 else 569 CheckExecutable pwd 570 let cmd = 'pwd' 571 endif 572 call mkdir('Xdir') 573 let buf = term_start(cmd, {'cwd': 'Xdir'}) 574 call WaitForAssert({-> assert_equal('Xdir', fnamemodify(getline(1), ":t"))}) 575 576 exe buf . 'bwipe' 577 call delete('Xdir', 'rf') 578endfunc 579 580func Test_terminal_cwd_failure() 581 " Case 1: Provided directory is not actually a directory. Attempt to make 582 " the file executable as well. 583 call writefile([], 'Xfile') 584 call setfperm('Xfile', 'rwx------') 585 call assert_fails("call term_start(&shell, {'cwd': 'Xfile'})", 'E475:') 586 call delete('Xfile') 587 588 " Case 2: Directory does not exist. 589 call assert_fails("call term_start(&shell, {'cwd': 'Xdir'})", 'E475:') 590 591 " Case 3: Directory exists but is not accessible. 592 " Skip this for root, it will be accessible anyway. 593 if !IsRoot() 594 call mkdir('XdirNoAccess', '', '0600') 595 " return early if the directory permissions could not be set properly 596 if getfperm('XdirNoAccess')[2] == 'x' 597 call delete('XdirNoAccess', 'rf') 598 return 599 endif 600 call assert_fails("call term_start(&shell, {'cwd': 'XdirNoAccess'})", 'E475:') 601 call delete('XdirNoAccess', 'rf') 602 endif 603endfunc 604 605func Test_terminal_servername() 606 if !has('clientserver') 607 return 608 endif 609 call s:test_environment("VIM_SERVERNAME", v:servername) 610endfunc 611 612func Test_terminal_version() 613 call s:test_environment("VIM_TERMINAL", string(v:version)) 614endfunc 615 616func s:test_environment(name, value) 617 let buf = Run_shell_in_terminal({}) 618 " Wait for the shell to display a prompt 619 call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) 620 if has('win32') 621 call term_sendkeys(buf, "echo %" . a:name . "%\r") 622 else 623 call term_sendkeys(buf, "echo $" . a:name . "\r") 624 endif 625 call term_wait(buf) 626 call StopShellInTerminal(buf) 627 call WaitForAssert({-> assert_equal(a:value, getline(2))}) 628 629 exe buf . 'bwipe' 630 unlet buf 631endfunc 632 633func Test_terminal_env() 634 let buf = Run_shell_in_terminal({'env': {'TESTENV': 'correct'}}) 635 " Wait for the shell to display a prompt 636 call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) 637 if has('win32') 638 call term_sendkeys(buf, "echo %TESTENV%\r") 639 else 640 call term_sendkeys(buf, "echo $TESTENV\r") 641 endif 642 eval buf->term_wait() 643 call StopShellInTerminal(buf) 644 call WaitForAssert({-> assert_equal('correct', getline(2))}) 645 646 exe buf . 'bwipe' 647endfunc 648 649func Test_terminal_list_args() 650 let buf = term_start([&shell, &shellcmdflag, 'echo "123"']) 651 call assert_fails(buf . 'bwipe', 'E517') 652 exe buf . 'bwipe!' 653 call assert_equal("", bufname(buf)) 654endfunction 655 656func Test_terminal_noblock() 657 let buf = term_start(&shell) 658 if has('bsd') || has('mac') || has('sun') 659 " The shell or something else has a problem dealing with more than 1000 660 " characters at the same time. 661 let len = 1000 662 " NPFS is used in Windows, nonblocking mode does not work properly. 663 elseif has('win32') 664 let len = 1 665 else 666 let len = 5000 667 endif 668 669 for c in ['a','b','c','d','e','f','g','h','i','j','k'] 670 call term_sendkeys(buf, 'echo ' . repeat(c, len) . "\<cr>") 671 endfor 672 call term_sendkeys(buf, "echo done\<cr>") 673 674 " On MS-Windows there is an extra empty line below "done". Find "done" in 675 " the last-but-one or the last-but-two line. 676 let lnum = term_getsize(buf)[0] - 1 677 call WaitFor({-> term_getline(buf, lnum) =~ "done" || term_getline(buf, lnum - 1) =~ "done"}, 10000) 678 let line = term_getline(buf, lnum) 679 if line !~ 'done' 680 let line = term_getline(buf, lnum - 1) 681 endif 682 call assert_match('done', line) 683 684 let g:job = term_getjob(buf) 685 call StopShellInTerminal(buf) 686 call term_wait(buf) 687 unlet g:job 688 bwipe 689endfunc 690 691func Test_terminal_write_stdin() 692 " TODO: enable once writing to stdin works on MS-Windows 693 CheckNotMSWindows 694 CheckExecutable wc 695 696 call setline(1, ['one', 'two', 'three']) 697 %term wc 698 call WaitForAssert({-> assert_match('3', getline("$"))}) 699 let nrs = split(getline('$')) 700 call assert_equal(['3', '3', '14'], nrs) 701 %bwipe! 702 703 call setline(1, ['one', 'two', 'three', 'four']) 704 2,3term wc 705 call WaitForAssert({-> assert_match('2', getline("$"))}) 706 let nrs = split(getline('$')) 707 call assert_equal(['2', '2', '10'], nrs) 708 %bwipe! 709endfunc 710 711func Test_terminal_eof_arg() 712 CheckExecutable python 713 714 call setline(1, ['print("hello")']) 715 1term ++eof=exit(123) python 716 " MS-Windows echoes the input, Unix doesn't. 717 if has('win32') 718 call WaitFor({-> getline('$') =~ 'exit(123)'}) 719 call assert_equal('hello', getline(line('$') - 1)) 720 else 721 call WaitFor({-> getline('$') =~ 'hello'}) 722 call assert_equal('hello', getline('$')) 723 endif 724 call assert_equal(123, bufnr()->term_getjob()->job_info().exitval) 725 %bwipe! 726endfunc 727 728func Test_terminal_eof_arg_win32_ctrl_z() 729 CheckMSWindows 730 CheckExecutable python 731 732 call setline(1, ['print("hello")']) 733 1term ++eof=<C-Z> python 734 call WaitForAssert({-> assert_match('\^Z', getline(line('$') - 1))}) 735 call assert_match('\^Z', getline(line('$') - 1)) 736 %bwipe! 737endfunc 738 739func Test_terminal_duplicate_eof_arg() 740 CheckExecutable python 741 742 " Check the last specified ++eof arg is used and should not memory leak. 743 new 744 call setline(1, ['print("hello")']) 745 1term ++eof=<C-Z> ++eof=exit(123) python 746 " MS-Windows echoes the input, Unix doesn't. 747 if has('win32') 748 call WaitFor({-> getline('$') =~ 'exit(123)'}) 749 call assert_equal('hello', getline(line('$') - 1)) 750 else 751 call WaitFor({-> getline('$') =~ 'hello'}) 752 call assert_equal('hello', getline('$')) 753 endif 754 call assert_equal(123, bufnr()->term_getjob()->job_info().exitval) 755 %bwipe! 756endfunc 757 758func Test_terminal_no_cmd() 759 let buf = term_start('NONE', {}) 760 call assert_notequal(0, buf) 761 762 let pty = job_info(term_getjob(buf))['tty_out'] 763 call assert_notequal('', pty) 764 if has('gui_running') && !has('win32') 765 " In the GUI job_start() doesn't work, it does not read from the pty. 766 call system('echo "look here" > ' . pty) 767 else 768 " Otherwise using a job works on all systems. 769 call job_start([&shell, &shellcmdflag, 'echo "look here" > ' . pty]) 770 endif 771 call WaitForAssert({-> assert_match('look here', term_getline(buf, 1))}) 772 773 bwipe! 774endfunc 775 776func Test_terminal_special_chars() 777 " this file name only works on Unix 778 CheckUnix 779 780 call mkdir('Xdir with spaces') 781 call writefile(['x'], 'Xdir with spaces/quoted"file') 782 term ls Xdir\ with\ spaces/quoted\"file 783 call WaitForAssert({-> assert_match('quoted"file', term_getline('', 1))}) 784 " make sure the job has finished 785 call WaitForAssert({-> assert_match('finish', term_getstatus(bufnr()))}) 786 787 call delete('Xdir with spaces', 'rf') 788 bwipe 789endfunc 790 791func Test_terminal_wrong_options() 792 call assert_fails('call term_start(&shell, { 793 \ "in_io": "file", 794 \ "in_name": "xxx", 795 \ "out_io": "file", 796 \ "out_name": "xxx", 797 \ "err_io": "file", 798 \ "err_name": "xxx" 799 \ })', 'E474:') 800 call assert_fails('call term_start(&shell, { 801 \ "out_buf": bufnr("%") 802 \ })', 'E474:') 803 call assert_fails('call term_start(&shell, { 804 \ "err_buf": bufnr("%") 805 \ })', 'E474:') 806endfunc 807 808func Test_terminal_redir_file() 809 let cmd = Get_cat_123_cmd() 810 let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'}) 811 call term_wait(buf) 812 " ConPTY may precede escape sequence. There are things that are not so. 813 if !has('conpty') 814 call WaitForAssert({-> assert_notequal(0, len(readfile("Xfile")))}) 815 call assert_match('123', readfile('Xfile')[0]) 816 endif 817 let g:job = term_getjob(buf) 818 call WaitForAssert({-> assert_equal("dead", job_status(g:job))}) 819 call delete('Xfile') 820 bwipe 821 822 if has('unix') 823 call writefile(['one line'], 'Xfile') 824 let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'}) 825 call term_wait(buf) 826 call WaitForAssert({-> assert_equal('one line', term_getline(buf, 1))}) 827 let g:job = term_getjob(buf) 828 call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) 829 bwipe 830 call delete('Xfile') 831 endif 832endfunc 833 834func TerminalTmap(remap) 835 let buf = Run_shell_in_terminal({}) 836 call assert_equal('t', mode()) 837 838 if a:remap 839 tmap 123 456 840 else 841 tnoremap 123 456 842 endif 843 " don't use abcde, it's an existing command 844 tmap 456 abxde 845 call assert_equal('456', maparg('123', 't')) 846 call assert_equal('abxde', maparg('456', 't')) 847 call feedkeys("123", 'tx') 848 call WaitForAssert({-> assert_match('abxde\|456', term_getline(buf, term_getcursor(buf)[0]))}) 849 let lnum = term_getcursor(buf)[0] 850 if a:remap 851 call assert_match('abxde', term_getline(buf, lnum)) 852 else 853 call assert_match('456', term_getline(buf, lnum)) 854 endif 855 856 call term_sendkeys(buf, "\r") 857 call StopShellInTerminal(buf) 858 call term_wait(buf) 859 860 tunmap 123 861 tunmap 456 862 call assert_equal('', maparg('123', 't')) 863 close 864 unlet g:job 865endfunc 866 867func Test_terminal_tmap() 868 call TerminalTmap(1) 869 call TerminalTmap(0) 870endfunc 871 872func Test_terminal_wall() 873 let buf = Run_shell_in_terminal({}) 874 wall 875 call StopShellInTerminal(buf) 876 call term_wait(buf) 877 exe buf . 'bwipe' 878 unlet g:job 879endfunc 880 881func Test_terminal_wqall() 882 let buf = Run_shell_in_terminal({}) 883 call assert_fails('wqall', 'E948') 884 call StopShellInTerminal(buf) 885 call term_wait(buf) 886 exe buf . 'bwipe' 887 unlet g:job 888endfunc 889 890func Test_terminal_composing_unicode() 891 CheckNotBSD 892 let save_enc = &encoding 893 set encoding=utf-8 894 895 if has('win32') 896 let cmd = "cmd /K chcp 65001" 897 let lnum = [3, 6, 9] 898 else 899 let cmd = &shell 900 let lnum = [1, 3, 5] 901 endif 902 903 enew 904 let buf = term_start(cmd, {'curwin': bufnr('')}) 905 let g:job = term_getjob(buf) 906 call term_wait(buf, 50) 907 908 if has('win32') 909 call assert_equal('cmd', job_info(g:job).cmd[0]) 910 else 911 call assert_equal(&shell, job_info(g:job).cmd[0]) 912 endif 913 914 " ascii + composing 915 let txt = "a\u0308bc" 916 call term_sendkeys(buf, "echo " . txt . "\r") 917 call term_wait(buf, 50) 918 call assert_match("echo " . txt, term_getline(buf, lnum[0])) 919 call assert_equal(txt, term_getline(buf, lnum[0] + 1)) 920 let l = term_scrape(buf, lnum[0] + 1) 921 call assert_equal("a\u0308", l[0].chars) 922 call assert_equal("b", l[1].chars) 923 call assert_equal("c", l[2].chars) 924 925 " multibyte + composing 926 let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099" 927 call term_sendkeys(buf, "echo " . txt . "\r") 928 call term_wait(buf, 50) 929 call assert_match("echo " . txt, term_getline(buf, lnum[1])) 930 call assert_equal(txt, term_getline(buf, lnum[1] + 1)) 931 let l = term_scrape(buf, lnum[1] + 1) 932 call assert_equal("\u304b\u3099", l[0].chars) 933 call assert_equal("\u304e", l[1].chars) 934 call assert_equal("\u304f\u3099", l[2].chars) 935 call assert_equal("\u3052", l[3].chars) 936 call assert_equal("\u3053\u3099", l[4].chars) 937 938 " \u00a0 + composing 939 let txt = "abc\u00a0\u0308" 940 call term_sendkeys(buf, "echo " . txt . "\r") 941 call term_wait(buf, 50) 942 call assert_match("echo " . txt, term_getline(buf, lnum[2])) 943 call assert_equal(txt, term_getline(buf, lnum[2] + 1)) 944 let l = term_scrape(buf, lnum[2] + 1) 945 call assert_equal("\u00a0\u0308", l[3].chars) 946 947 call term_sendkeys(buf, "exit\r") 948 call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) 949 bwipe! 950 unlet g:job 951 let &encoding = save_enc 952endfunc 953 954func Test_terminal_aucmd_on_close() 955 fun Nop() 956 let s:called = 1 957 endfun 958 959 aug repro 960 au! 961 au BufWinLeave * call Nop() 962 aug END 963 964 let [cmd, waittime] = s:get_sleep_cmd() 965 966 call assert_equal(1, winnr('$')) 967 new 968 call setline(1, ['one', 'two']) 969 exe 'term ++close ' . cmd 970 wincmd p 971 call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) 972 call assert_equal(1, s:called) 973 bwipe! 974 975 unlet s:called 976 au! repro 977 delfunc Nop 978endfunc 979 980func Test_terminal_term_start_empty_command() 981 let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})" 982 call assert_fails(cmd, 'E474') 983 let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})" 984 call assert_fails(cmd, 'E474') 985 let cmd = "call term_start({}, {'curwin' : 1, 'term_finish' : 'close'})" 986 call assert_fails(cmd, 'E474') 987 let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})" 988 call assert_fails(cmd, 'E474') 989endfunc 990 991func Test_terminal_response_to_control_sequence() 992 CheckUnix 993 994 let buf = Run_shell_in_terminal({}) 995 call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) 996 997 call term_sendkeys(buf, "cat\<CR>") 998 call WaitForAssert({-> assert_match('cat', term_getline(buf, 1))}) 999 1000 " Request the cursor position. 1001 call term_sendkeys(buf, "\x1b[6n\<CR>") 1002 1003 " Wait for output from tty to display, below an empty line. 1004 call WaitForAssert({-> assert_match('3;1R', term_getline(buf, 4))}) 1005 1006 " End "cat" gently. 1007 call term_sendkeys(buf, "\<CR>\<C-D>") 1008 1009 call StopShellInTerminal(buf) 1010 exe buf . 'bwipe' 1011 unlet g:job 1012endfunc 1013 1014" Run Vim, start a terminal in that Vim with the kill argument, 1015" :qall works. 1016func Run_terminal_qall_kill(line1, line2) 1017 " 1. Open a terminal window and wait for the prompt to appear 1018 " 2. set kill using term_setkill() 1019 " 3. make Vim exit, it will kill the shell 1020 let after = [ 1021 \ a:line1, 1022 \ 'let buf = bufnr("%")', 1023 \ 'while term_getline(buf, 1) =~ "^\\s*$"', 1024 \ ' sleep 10m', 1025 \ 'endwhile', 1026 \ a:line2, 1027 \ 'au VimLeavePre * call writefile(["done"], "Xdone")', 1028 \ 'qall', 1029 \ ] 1030 if !RunVim([], after, '') 1031 return 1032 endif 1033 call assert_equal("done", readfile("Xdone")[0]) 1034 call delete("Xdone") 1035endfunc 1036 1037" Run Vim in a terminal, then start a terminal in that Vim with a kill 1038" argument, check that :qall works. 1039func Test_terminal_qall_kill_arg() 1040 call Run_terminal_qall_kill('term ++kill=kill', '') 1041endfunc 1042 1043" Run Vim, start a terminal in that Vim, set the kill argument with 1044" term_setkill(), check that :qall works. 1045func Test_terminal_qall_kill_func() 1046 call Run_terminal_qall_kill('term', 'eval buf->term_setkill("kill")') 1047endfunc 1048 1049" Run Vim, start a terminal in that Vim without the kill argument, 1050" check that :qall does not exit, :qall! does. 1051func Test_terminal_qall_exit() 1052 let after =<< trim [CODE] 1053 term 1054 let buf = bufnr("%") 1055 while term_getline(buf, 1) =~ "^\\s*$" 1056 sleep 10m 1057 endwhile 1058 set nomore 1059 au VimLeavePre * call writefile(["too early"], "Xdone") 1060 qall 1061 au! VimLeavePre * exe buf . "bwipe!" | call writefile(["done"], "Xdone") 1062 cquit 1063 [CODE] 1064 1065 if !RunVim([], after, '') 1066 return 1067 endif 1068 call assert_equal("done", readfile("Xdone")[0]) 1069 call delete("Xdone") 1070endfunc 1071 1072" Run Vim in a terminal, then start a terminal in that Vim without a kill 1073" argument, check that :confirm qall works. 1074func Test_terminal_qall_prompt() 1075 CheckRunVimInTerminal 1076 let buf = RunVimInTerminal('', {}) 1077 1078 " Open a terminal window and wait for the prompt to appear 1079 call term_sendkeys(buf, ":term\<CR>") 1080 call WaitForAssert({-> assert_match('\[running]', term_getline(buf, 10))}) 1081 call WaitForAssert({-> assert_notmatch('^\s*$', term_getline(buf, 1))}) 1082 1083 " make Vim exit, it will prompt to kill the shell 1084 call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>") 1085 call WaitForAssert({-> assert_match('ancel:', term_getline(buf, 20))}) 1086 call term_sendkeys(buf, "y") 1087 call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))}) 1088 1089 " close the terminal window where Vim was running 1090 quit 1091endfunc 1092 1093" Run Vim in a terminal, then start a terminal window with a shell and check 1094" that Vim exits if it is closed. 1095func Test_terminal_exit() 1096 CheckRunVimInTerminal 1097 1098 let lines =<< trim END 1099 let winid = win_getid() 1100 help 1101 term 1102 let termid = win_getid() 1103 call win_gotoid(winid) 1104 close 1105 call win_gotoid(termid) 1106 END 1107 call writefile(lines, 'XtermExit') 1108 let buf = RunVimInTerminal('-S XtermExit', #{rows: 10}) 1109 let job = term_getjob(buf) 1110 call WaitForAssert({-> assert_equal("run", job_status(job))}) 1111 1112 " quit the shell, it will make Vim exit 1113 call term_sendkeys(buf, "exit\<CR>") 1114 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 1115 1116 call delete('XtermExit') 1117endfunc 1118 1119func Test_terminal_open_autocmd() 1120 augroup repro 1121 au! 1122 au TerminalOpen * let s:called += 1 1123 augroup END 1124 1125 let s:called = 0 1126 1127 " Open a terminal window with :terminal 1128 terminal 1129 call assert_equal(1, s:called) 1130 bwipe! 1131 1132 " Open a terminal window with term_start() 1133 call term_start(&shell) 1134 call assert_equal(2, s:called) 1135 bwipe! 1136 1137 " Open a hidden terminal buffer with :terminal 1138 terminal ++hidden 1139 call assert_equal(3, s:called) 1140 for buf in term_list() 1141 exe buf . "bwipe!" 1142 endfor 1143 1144 " Open a hidden terminal buffer with term_start() 1145 let buf = term_start(&shell, {'hidden': 1}) 1146 call assert_equal(4, s:called) 1147 exe buf . "bwipe!" 1148 1149 unlet s:called 1150 au! repro 1151endfunction 1152 1153func Check_dump01(off) 1154 call assert_equal('one two three four five', trim(getline(a:off + 1))) 1155 call assert_equal('~ Select Word', trim(getline(a:off + 7))) 1156 call assert_equal(':popup PopUp', trim(getline(a:off + 20))) 1157endfunc 1158 1159func Test_terminal_dumpwrite_composing() 1160 CheckRunVimInTerminal 1161 let save_enc = &encoding 1162 set encoding=utf-8 1163 call assert_equal(1, winnr('$')) 1164 1165 let text = " a\u0300 e\u0302 o\u0308" 1166 call writefile([text], 'Xcomposing') 1167 let buf = RunVimInTerminal('--cmd "set encoding=utf-8" Xcomposing', {}) 1168 call WaitForAssert({-> assert_match(text, term_getline(buf, 1))}) 1169 eval 'Xdump'->term_dumpwrite(buf) 1170 let dumpline = readfile('Xdump')[0] 1171 call assert_match('|à| |ê| |ö', dumpline) 1172 1173 call StopVimInTerminal(buf) 1174 call delete('Xcomposing') 1175 call delete('Xdump') 1176 let &encoding = save_enc 1177endfunc 1178 1179" just testing basic functionality. 1180func Test_terminal_dumpload() 1181 let curbuf = winbufnr('') 1182 call assert_equal(1, winnr('$')) 1183 let buf = term_dumpload('dumps/Test_popup_command_01.dump') 1184 call assert_equal(2, winnr('$')) 1185 call assert_equal(20, line('$')) 1186 call Check_dump01(0) 1187 1188 " Load another dump in the same window 1189 let buf2 = 'dumps/Test_diff_01.dump'->term_dumpload({'bufnr': buf}) 1190 call assert_equal(buf, buf2) 1191 call assert_notequal('one two three four five', trim(getline(1))) 1192 1193 " Load the first dump again in the same window 1194 let buf2 = term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': buf}) 1195 call assert_equal(buf, buf2) 1196 call Check_dump01(0) 1197 1198 call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': curbuf})", 'E475:') 1199 call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': 9999})", 'E86:') 1200 new 1201 let closedbuf = winbufnr('') 1202 quit 1203 call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': closedbuf})", 'E475:') 1204 1205 quit 1206endfunc 1207 1208func Test_terminal_dumpload_dump() 1209 CheckRunVimInTerminal 1210 1211 let lines =<< trim END 1212 call term_dumpload('dumps/Test_popupwin_22.dump', #{term_rows: 12}) 1213 END 1214 call writefile(lines, 'XtermDumpload') 1215 let buf = RunVimInTerminal('-S XtermDumpload', #{rows: 15}) 1216 call VerifyScreenDump(buf, 'Test_terminal_dumpload', {}) 1217 1218 call StopVimInTerminal(buf) 1219 call delete('XtermDumpload') 1220endfunc 1221 1222func Test_terminal_dumpdiff() 1223 call assert_equal(1, winnr('$')) 1224 eval 'dumps/Test_popup_command_01.dump'->term_dumpdiff('dumps/Test_popup_command_02.dump') 1225 call assert_equal(2, winnr('$')) 1226 call assert_equal(62, line('$')) 1227 call Check_dump01(0) 1228 call Check_dump01(42) 1229 call assert_equal(' bbbbbbbbbbbbbbbbbb ', getline(26)[0:29]) 1230 quit 1231endfunc 1232 1233func Test_terminal_dumpdiff_swap() 1234 call assert_equal(1, winnr('$')) 1235 call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_03.dump') 1236 call assert_equal(2, winnr('$')) 1237 call assert_equal(62, line('$')) 1238 call assert_match('Test_popup_command_01.dump', getline(21)) 1239 call assert_match('Test_popup_command_03.dump', getline(42)) 1240 call assert_match('Undo', getline(3)) 1241 call assert_match('three four five', getline(45)) 1242 1243 normal s 1244 call assert_match('Test_popup_command_03.dump', getline(21)) 1245 call assert_match('Test_popup_command_01.dump', getline(42)) 1246 call assert_match('three four five', getline(3)) 1247 call assert_match('Undo', getline(45)) 1248 quit 1249endfunc 1250 1251func Test_terminal_dumpdiff_options() 1252 set laststatus=0 1253 call assert_equal(1, winnr('$')) 1254 let height = winheight(0) 1255 call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 1, 'term_cols': 33}) 1256 call assert_equal(2, winnr('$')) 1257 call assert_equal(height, winheight(winnr())) 1258 call assert_equal(33, winwidth(winnr())) 1259 call assert_equal('dump diff dumps/Test_popup_command_01.dump', bufname('%')) 1260 quit 1261 1262 call assert_equal(1, winnr('$')) 1263 call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 0, 'term_rows': 13, 'term_name': 'something else'}) 1264 call assert_equal(2, winnr('$')) 1265 call assert_equal(&columns, winwidth(0)) 1266 call assert_equal(13, winheight(0)) 1267 call assert_equal('something else', bufname('%')) 1268 quit 1269 1270 call assert_equal(1, winnr('$')) 1271 call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1}) 1272 call assert_equal(1, winnr('$')) 1273 bwipe 1274 1275 set laststatus& 1276endfunc 1277 1278func Api_drop_common(options) 1279 call assert_equal(1, winnr('$')) 1280 1281 " Use the title termcap entries to output the escape sequence. 1282 call writefile([ 1283 \ 'set title', 1284 \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"', 1285 \ 'let &titlestring = ''["drop","Xtextfile"' . a:options . ']''', 1286 \ 'redraw', 1287 \ "set t_ts=", 1288 \ ], 'Xscript') 1289 let buf = RunVimInTerminal('-S Xscript', {}) 1290 call WaitFor({-> bufnr('Xtextfile') > 0}) 1291 call assert_equal('Xtextfile', expand('%:t')) 1292 call assert_true(winnr('$') >= 3) 1293 return buf 1294endfunc 1295 1296func Test_terminal_api_drop_newwin() 1297 CheckRunVimInTerminal 1298 let buf = Api_drop_common('') 1299 call assert_equal(0, &bin) 1300 call assert_equal('', &fenc) 1301 1302 call StopVimInTerminal(buf) 1303 call delete('Xscript') 1304 bwipe Xtextfile 1305endfunc 1306 1307func Test_terminal_api_drop_newwin_bin() 1308 CheckRunVimInTerminal 1309 let buf = Api_drop_common(',{"bin":1}') 1310 call assert_equal(1, &bin) 1311 1312 call StopVimInTerminal(buf) 1313 call delete('Xscript') 1314 bwipe Xtextfile 1315endfunc 1316 1317func Test_terminal_api_drop_newwin_binary() 1318 CheckRunVimInTerminal 1319 let buf = Api_drop_common(',{"binary":1}') 1320 call assert_equal(1, &bin) 1321 1322 call StopVimInTerminal(buf) 1323 call delete('Xscript') 1324 bwipe Xtextfile 1325endfunc 1326 1327func Test_terminal_api_drop_newwin_nobin() 1328 CheckRunVimInTerminal 1329 set binary 1330 let buf = Api_drop_common(',{"nobin":1}') 1331 call assert_equal(0, &bin) 1332 1333 call StopVimInTerminal(buf) 1334 call delete('Xscript') 1335 bwipe Xtextfile 1336 set nobinary 1337endfunc 1338 1339func Test_terminal_api_drop_newwin_nobinary() 1340 CheckRunVimInTerminal 1341 set binary 1342 let buf = Api_drop_common(',{"nobinary":1}') 1343 call assert_equal(0, &bin) 1344 1345 call StopVimInTerminal(buf) 1346 call delete('Xscript') 1347 bwipe Xtextfile 1348 set nobinary 1349endfunc 1350 1351func Test_terminal_api_drop_newwin_ff() 1352 CheckRunVimInTerminal 1353 let buf = Api_drop_common(',{"ff":"dos"}') 1354 call assert_equal("dos", &ff) 1355 1356 call StopVimInTerminal(buf) 1357 call delete('Xscript') 1358 bwipe Xtextfile 1359endfunc 1360 1361func Test_terminal_api_drop_newwin_fileformat() 1362 CheckRunVimInTerminal 1363 let buf = Api_drop_common(',{"fileformat":"dos"}') 1364 call assert_equal("dos", &ff) 1365 1366 call StopVimInTerminal(buf) 1367 call delete('Xscript') 1368 bwipe Xtextfile 1369endfunc 1370 1371func Test_terminal_api_drop_newwin_enc() 1372 CheckRunVimInTerminal 1373 let buf = Api_drop_common(',{"enc":"utf-16"}') 1374 call assert_equal("utf-16", &fenc) 1375 1376 call StopVimInTerminal(buf) 1377 call delete('Xscript') 1378 bwipe Xtextfile 1379endfunc 1380 1381func Test_terminal_api_drop_newwin_encoding() 1382 CheckRunVimInTerminal 1383 let buf = Api_drop_common(',{"encoding":"utf-16"}') 1384 call assert_equal("utf-16", &fenc) 1385 1386 call StopVimInTerminal(buf) 1387 call delete('Xscript') 1388 bwipe Xtextfile 1389endfunc 1390 1391func Test_terminal_api_drop_oldwin() 1392 CheckRunVimInTerminal 1393 let firstwinid = win_getid() 1394 split Xtextfile 1395 let textfile_winid = win_getid() 1396 call assert_equal(2, winnr('$')) 1397 call win_gotoid(firstwinid) 1398 1399 " Use the title termcap entries to output the escape sequence. 1400 call writefile([ 1401 \ 'set title', 1402 \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"', 1403 \ 'let &titlestring = ''["drop","Xtextfile"]''', 1404 \ 'redraw', 1405 \ "set t_ts=", 1406 \ ], 'Xscript') 1407 let buf = RunVimInTerminal('-S Xscript', {'rows': 10}) 1408 call WaitForAssert({-> assert_equal('Xtextfile', expand('%:t'))}) 1409 call assert_equal(textfile_winid, win_getid()) 1410 1411 call StopVimInTerminal(buf) 1412 call delete('Xscript') 1413 bwipe Xtextfile 1414endfunc 1415 1416func Tapi_TryThis(bufnum, arg) 1417 let g:called_bufnum = a:bufnum 1418 let g:called_arg = a:arg 1419endfunc 1420 1421func WriteApiCall(funcname) 1422 " Use the title termcap entries to output the escape sequence. 1423 call writefile([ 1424 \ 'set title', 1425 \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"', 1426 \ 'let &titlestring = ''["call","' . a:funcname . '",["hello",123]]''', 1427 \ 'redraw', 1428 \ "set t_ts=", 1429 \ ], 'Xscript') 1430endfunc 1431 1432func Test_terminal_api_call() 1433 CheckRunVimInTerminal 1434 1435 unlet! g:called_bufnum 1436 unlet! g:called_arg 1437 1438 call WriteApiCall('Tapi_TryThis') 1439 1440 " Default 1441 let buf = RunVimInTerminal('-S Xscript', {}) 1442 call WaitFor({-> exists('g:called_bufnum')}) 1443 call assert_equal(buf, g:called_bufnum) 1444 call assert_equal(['hello', 123], g:called_arg) 1445 call StopVimInTerminal(buf) 1446 1447 unlet! g:called_bufnum 1448 unlet! g:called_arg 1449 1450 " Enable explicitly 1451 let buf = RunVimInTerminal('-S Xscript', {'term_api': 'Tapi_Try'}) 1452 call WaitFor({-> exists('g:called_bufnum')}) 1453 call assert_equal(buf, g:called_bufnum) 1454 call assert_equal(['hello', 123], g:called_arg) 1455 call StopVimInTerminal(buf) 1456 1457 unlet! g:called_bufnum 1458 unlet! g:called_arg 1459 1460 func! ApiCall_TryThis(bufnum, arg) 1461 let g:called_bufnum2 = a:bufnum 1462 let g:called_arg2 = a:arg 1463 endfunc 1464 1465 call WriteApiCall('ApiCall_TryThis') 1466 1467 " Use prefix match 1468 let buf = RunVimInTerminal('-S Xscript', {'term_api': 'ApiCall_'}) 1469 call WaitFor({-> exists('g:called_bufnum2')}) 1470 call assert_equal(buf, g:called_bufnum2) 1471 call assert_equal(['hello', 123], g:called_arg2) 1472 call StopVimInTerminal(buf) 1473 1474 unlet! g:called_bufnum2 1475 unlet! g:called_arg2 1476 1477 call delete('Xscript') 1478 delfunction! ApiCall_TryThis 1479 unlet! g:called_bufnum2 1480 unlet! g:called_arg2 1481endfunc 1482 1483func Test_terminal_api_call_fails() 1484 CheckRunVimInTerminal 1485 1486 func! TryThis(bufnum, arg) 1487 let g:called_bufnum3 = a:bufnum 1488 let g:called_arg3 = a:arg 1489 endfunc 1490 1491 call WriteApiCall('TryThis') 1492 1493 unlet! g:called_bufnum3 1494 unlet! g:called_arg3 1495 1496 " Not permitted 1497 call ch_logfile('Xlog', 'w') 1498 let buf = RunVimInTerminal('-S Xscript', {'term_api': ''}) 1499 call WaitForAssert({-> assert_match('Unpermitted function: TryThis', string(readfile('Xlog')))}) 1500 call assert_false(exists('g:called_bufnum3')) 1501 call assert_false(exists('g:called_arg3')) 1502 call StopVimInTerminal(buf) 1503 1504 " No match 1505 call ch_logfile('Xlog', 'w') 1506 let buf = RunVimInTerminal('-S Xscript', {'term_api': 'TryThat'}) 1507 call WaitFor({-> string(readfile('Xlog')) =~ 'Unpermitted function: TryThis'}) 1508 call assert_false(exists('g:called_bufnum3')) 1509 call assert_false(exists('g:called_arg3')) 1510 call StopVimInTerminal(buf) 1511 1512 call delete('Xscript') 1513 call ch_logfile('') 1514 call delete('Xlog') 1515 delfunction! TryThis 1516 unlet! g:called_bufnum3 1517 unlet! g:called_arg3 1518endfunc 1519 1520let s:caught_e937 = 0 1521 1522func Tapi_Delete(bufnum, arg) 1523 try 1524 execute 'bdelete!' a:bufnum 1525 catch /E937:/ 1526 let s:caught_e937 = 1 1527 endtry 1528endfunc 1529 1530func Test_terminal_api_call_fail_delete() 1531 CheckRunVimInTerminal 1532 1533 call WriteApiCall('Tapi_Delete') 1534 let buf = RunVimInTerminal('-S Xscript', {}) 1535 call WaitForAssert({-> assert_equal(1, s:caught_e937)}) 1536 1537 call StopVimInTerminal(buf) 1538 call delete('Xscript') 1539 call ch_logfile('', '') 1540endfunc 1541 1542func Test_terminal_ansicolors_default() 1543 if !exists('*term_getansicolors') 1544 throw 'Skipped: term_getansicolors() not supported' 1545 endif 1546 let colors = [ 1547 \ '#000000', '#e00000', 1548 \ '#00e000', '#e0e000', 1549 \ '#0000e0', '#e000e0', 1550 \ '#00e0e0', '#e0e0e0', 1551 \ '#808080', '#ff4040', 1552 \ '#40ff40', '#ffff40', 1553 \ '#4040ff', '#ff40ff', 1554 \ '#40ffff', '#ffffff', 1555 \] 1556 1557 let buf = Run_shell_in_terminal({}) 1558 call assert_equal(colors, term_getansicolors(buf)) 1559 call StopShellInTerminal(buf) 1560 call term_wait(buf) 1561 1562 exe buf . 'bwipe' 1563endfunc 1564 1565let s:test_colors = [ 1566 \ '#616e64', '#0d0a79', 1567 \ '#6d610d', '#0a7373', 1568 \ '#690d0a', '#6d696e', 1569 \ '#0d0a6f', '#616e0d', 1570 \ '#0a6479', '#6d0d0a', 1571 \ '#617373', '#0d0a69', 1572 \ '#6d690d', '#0a6e6f', 1573 \ '#610d0a', '#6e6479', 1574 \] 1575 1576func Test_terminal_ansicolors_global() 1577 CheckFeature termguicolors 1578 if !exists('*term_getansicolors') 1579 throw 'Skipped: term_getansicolors() not supported' 1580 endif 1581 let g:terminal_ansi_colors = reverse(copy(s:test_colors)) 1582 let buf = Run_shell_in_terminal({}) 1583 call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf)) 1584 call StopShellInTerminal(buf) 1585 call term_wait(buf) 1586 1587 exe buf . 'bwipe' 1588 unlet g:terminal_ansi_colors 1589endfunc 1590 1591func Test_terminal_ansicolors_func() 1592 CheckFeature termguicolors 1593 if !exists('*term_getansicolors') 1594 throw 'Skipped: term_getansicolors() not supported' 1595 endif 1596 let g:terminal_ansi_colors = reverse(copy(s:test_colors)) 1597 let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors}) 1598 call assert_equal(s:test_colors, term_getansicolors(buf)) 1599 1600 call term_setansicolors(buf, g:terminal_ansi_colors) 1601 call assert_equal(g:terminal_ansi_colors, buf->term_getansicolors()) 1602 1603 let colors = [ 1604 \ 'ivory', 'AliceBlue', 1605 \ 'grey67', 'dark goldenrod', 1606 \ 'SteelBlue3', 'PaleVioletRed4', 1607 \ 'MediumPurple2', 'yellow2', 1608 \ 'RosyBrown3', 'OrangeRed2', 1609 \ 'white smoke', 'navy blue', 1610 \ 'grey47', 'gray97', 1611 \ 'MistyRose2', 'DodgerBlue4', 1612 \] 1613 eval buf->term_setansicolors(colors) 1614 1615 let colors[4] = 'Invalid' 1616 call assert_fails('call term_setansicolors(buf, colors)', 'E474:') 1617 1618 call StopShellInTerminal(buf) 1619 call term_wait(buf) 1620 exe buf . 'bwipe' 1621endfunc 1622 1623func Test_terminal_all_ansi_colors() 1624 CheckRunVimInTerminal 1625 1626 " Use all the ANSI colors. 1627 call writefile([ 1628 \ 'call setline(1, "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPP XXYYZZ")', 1629 \ 'hi Tblack ctermfg=0 ctermbg=8', 1630 \ 'hi Tdarkred ctermfg=1 ctermbg=9', 1631 \ 'hi Tdarkgreen ctermfg=2 ctermbg=10', 1632 \ 'hi Tbrown ctermfg=3 ctermbg=11', 1633 \ 'hi Tdarkblue ctermfg=4 ctermbg=12', 1634 \ 'hi Tdarkmagenta ctermfg=5 ctermbg=13', 1635 \ 'hi Tdarkcyan ctermfg=6 ctermbg=14', 1636 \ 'hi Tlightgrey ctermfg=7 ctermbg=15', 1637 \ 'hi Tdarkgrey ctermfg=8 ctermbg=0', 1638 \ 'hi Tred ctermfg=9 ctermbg=1', 1639 \ 'hi Tgreen ctermfg=10 ctermbg=2', 1640 \ 'hi Tyellow ctermfg=11 ctermbg=3', 1641 \ 'hi Tblue ctermfg=12 ctermbg=4', 1642 \ 'hi Tmagenta ctermfg=13 ctermbg=5', 1643 \ 'hi Tcyan ctermfg=14 ctermbg=6', 1644 \ 'hi Twhite ctermfg=15 ctermbg=7', 1645 \ 'hi TdarkredBold ctermfg=1 cterm=bold', 1646 \ 'hi TgreenBold ctermfg=10 cterm=bold', 1647 \ 'hi TmagentaBold ctermfg=13 cterm=bold ctermbg=5', 1648 \ '', 1649 \ 'call matchadd("Tblack", "A")', 1650 \ 'call matchadd("Tdarkred", "B")', 1651 \ 'call matchadd("Tdarkgreen", "C")', 1652 \ 'call matchadd("Tbrown", "D")', 1653 \ 'call matchadd("Tdarkblue", "E")', 1654 \ 'call matchadd("Tdarkmagenta", "F")', 1655 \ 'call matchadd("Tdarkcyan", "G")', 1656 \ 'call matchadd("Tlightgrey", "H")', 1657 \ 'call matchadd("Tdarkgrey", "I")', 1658 \ 'call matchadd("Tred", "J")', 1659 \ 'call matchadd("Tgreen", "K")', 1660 \ 'call matchadd("Tyellow", "L")', 1661 \ 'call matchadd("Tblue", "M")', 1662 \ 'call matchadd("Tmagenta", "N")', 1663 \ 'call matchadd("Tcyan", "O")', 1664 \ 'call matchadd("Twhite", "P")', 1665 \ 'call matchadd("TdarkredBold", "X")', 1666 \ 'call matchadd("TgreenBold", "Y")', 1667 \ 'call matchadd("TmagentaBold", "Z")', 1668 \ 'redraw', 1669 \ ], 'Xcolorscript') 1670 let buf = RunVimInTerminal('-S Xcolorscript', {'rows': 10}) 1671 call VerifyScreenDump(buf, 'Test_terminal_all_ansi_colors', {}) 1672 1673 call term_sendkeys(buf, ":q\<CR>") 1674 call StopVimInTerminal(buf) 1675 call delete('Xcolorscript') 1676endfunc 1677 1678func Test_terminal_termwinsize_option_fixed() 1679 CheckRunVimInTerminal 1680 set termwinsize=6x40 1681 let text = [] 1682 for n in range(10) 1683 call add(text, repeat(n, 50)) 1684 endfor 1685 call writefile(text, 'Xwinsize') 1686 let buf = RunVimInTerminal('Xwinsize', {}) 1687 let win = bufwinid(buf) 1688 call assert_equal([6, 40], term_getsize(buf)) 1689 call assert_equal(6, winheight(win)) 1690 call assert_equal(40, winwidth(win)) 1691 1692 " resizing the window doesn't resize the terminal. 1693 resize 10 1694 vertical resize 60 1695 call assert_equal([6, 40], term_getsize(buf)) 1696 call assert_equal(10, winheight(win)) 1697 call assert_equal(60, winwidth(win)) 1698 1699 call StopVimInTerminal(buf) 1700 call delete('Xwinsize') 1701 1702 call assert_fails('set termwinsize=40', 'E474') 1703 call assert_fails('set termwinsize=10+40', 'E474') 1704 call assert_fails('set termwinsize=abc', 'E474') 1705 1706 set termwinsize= 1707endfunc 1708 1709func Test_terminal_termwinsize_option_zero() 1710 set termwinsize=0x0 1711 let buf = Run_shell_in_terminal({}) 1712 let win = bufwinid(buf) 1713 call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) 1714 call StopShellInTerminal(buf) 1715 call term_wait(buf) 1716 exe buf . 'bwipe' 1717 1718 set termwinsize=7x0 1719 let buf = Run_shell_in_terminal({}) 1720 let win = bufwinid(buf) 1721 call assert_equal([7, winwidth(win)], term_getsize(buf)) 1722 call StopShellInTerminal(buf) 1723 call term_wait(buf) 1724 exe buf . 'bwipe' 1725 1726 set termwinsize=0x33 1727 let buf = Run_shell_in_terminal({}) 1728 let win = bufwinid(buf) 1729 call assert_equal([winheight(win), 33], term_getsize(buf)) 1730 call StopShellInTerminal(buf) 1731 call term_wait(buf) 1732 exe buf . 'bwipe' 1733 1734 set termwinsize= 1735endfunc 1736 1737func Test_terminal_termwinsize_minimum() 1738 set termwinsize=10*50 1739 vsplit 1740 let buf = Run_shell_in_terminal({}) 1741 let win = bufwinid(buf) 1742 call assert_inrange(10, 1000, winheight(win)) 1743 call assert_inrange(50, 1000, winwidth(win)) 1744 call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) 1745 1746 resize 15 1747 vertical resize 60 1748 redraw 1749 call assert_equal([15, 60], term_getsize(buf)) 1750 call assert_equal(15, winheight(win)) 1751 call assert_equal(60, winwidth(win)) 1752 1753 resize 7 1754 vertical resize 30 1755 redraw 1756 call assert_equal([10, 50], term_getsize(buf)) 1757 call assert_equal(7, winheight(win)) 1758 call assert_equal(30, winwidth(win)) 1759 1760 call StopShellInTerminal(buf) 1761 call term_wait(buf) 1762 exe buf . 'bwipe' 1763 1764 set termwinsize=0*0 1765 let buf = Run_shell_in_terminal({}) 1766 let win = bufwinid(buf) 1767 call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) 1768 call StopShellInTerminal(buf) 1769 call term_wait(buf) 1770 exe buf . 'bwipe' 1771 1772 set termwinsize= 1773endfunc 1774 1775func Test_terminal_termwinkey() 1776 " make three tabpages, terminal in the middle 1777 0tabnew 1778 tabnext 1779 tabnew 1780 tabprev 1781 call assert_equal(1, winnr('$')) 1782 call assert_equal(2, tabpagenr()) 1783 let thiswin = win_getid() 1784 1785 let buf = Run_shell_in_terminal({}) 1786 let termwin = bufwinid(buf) 1787 set termwinkey=<C-L> 1788 call feedkeys("\<C-L>w", 'tx') 1789 call assert_equal(thiswin, win_getid()) 1790 call feedkeys("\<C-W>w", 'tx') 1791 call assert_equal(termwin, win_getid()) 1792 1793 if has('langmap') 1794 set langmap=xjyk 1795 call feedkeys("\<C-L>x", 'tx') 1796 call assert_equal(thiswin, win_getid()) 1797 call feedkeys("\<C-W>y", 'tx') 1798 call assert_equal(termwin, win_getid()) 1799 set langmap= 1800 endif 1801 1802 call feedkeys("\<C-L>gt", "xt") 1803 call assert_equal(3, tabpagenr()) 1804 tabprev 1805 call assert_equal(2, tabpagenr()) 1806 call assert_equal(termwin, win_getid()) 1807 1808 call feedkeys("\<C-L>gT", "xt") 1809 call assert_equal(1, tabpagenr()) 1810 tabnext 1811 call assert_equal(2, tabpagenr()) 1812 call assert_equal(termwin, win_getid()) 1813 1814 let job = term_getjob(buf) 1815 call feedkeys("\<C-L>\<C-C>", 'tx') 1816 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 1817 1818 set termwinkey& 1819 tabnext 1820 tabclose 1821 tabprev 1822 tabclose 1823endfunc 1824 1825func Test_terminal_out_err() 1826 CheckUnix 1827 1828 call writefile([ 1829 \ '#!/bin/sh', 1830 \ 'echo "this is standard error" >&2', 1831 \ 'echo "this is standard out" >&1', 1832 \ ], 'Xechoerrout.sh') 1833 call setfperm('Xechoerrout.sh', 'rwxrwx---') 1834 1835 let outfile = 'Xtermstdout' 1836 let buf = term_start(['./Xechoerrout.sh'], {'out_io': 'file', 'out_name': outfile}) 1837 1838 call WaitFor({-> !empty(readfile(outfile)) && !empty(term_getline(buf, 1))}) 1839 call assert_equal(['this is standard out'], readfile(outfile)) 1840 call assert_equal('this is standard error', term_getline(buf, 1)) 1841 1842 call WaitForAssert({-> assert_equal('dead', job_status(term_getjob(buf)))}) 1843 exe buf . 'bwipe' 1844 call delete('Xechoerrout.sh') 1845 call delete(outfile) 1846endfunc 1847 1848func Test_termwinscroll() 1849 CheckUnix 1850 1851 " Let the terminal output more than 'termwinscroll' lines, some at the start 1852 " will be dropped. 1853 exe 'set termwinscroll=' . &lines 1854 let buf = term_start('/bin/sh') 1855 for i in range(1, &lines) 1856 call feedkeys("echo " . i . "\<CR>", 'xt') 1857 call WaitForAssert({-> assert_match(string(i), term_getline(buf, term_getcursor(buf)[0] - 1))}) 1858 endfor 1859 " Go to Terminal-Normal mode to update the buffer. 1860 call feedkeys("\<C-W>N", 'xt') 1861 call assert_inrange(&lines, &lines * 110 / 100 + winheight(0), line('$')) 1862 1863 " Every "echo nr" must only appear once 1864 let lines = getline(1, line('$')) 1865 for i in range(&lines - len(lines) / 2 + 2, &lines) 1866 let filtered = filter(copy(lines), {idx, val -> val =~ 'echo ' . i . '\>'}) 1867 call assert_equal(1, len(filtered), 'for "echo ' . i . '"') 1868 endfor 1869 1870 exe buf . 'bwipe!' 1871endfunc 1872 1873" Resizing the terminal window caused an ml_get error. 1874" TODO: This does not reproduce the original problem. 1875func Test_terminal_resize() 1876 set statusline=x 1877 terminal 1878 call assert_equal(2, winnr('$')) 1879 1880 " Fill the terminal with text. 1881 if has('win32') 1882 call feedkeys("dir\<CR>", 'xt') 1883 else 1884 call feedkeys("ls\<CR>", 'xt') 1885 endif 1886 " Go to Terminal-Normal mode for a moment. 1887 call feedkeys("\<C-W>N", 'xt') 1888 " Open a new window 1889 call feedkeys("i\<C-W>n", 'xt') 1890 call assert_equal(3, winnr('$')) 1891 redraw 1892 1893 close 1894 call assert_equal(2, winnr('$')) 1895 call feedkeys("exit\<CR>", 'xt') 1896 set statusline& 1897endfunc 1898 1899" must be nearly the last, we can't go back from GUI to terminal 1900func Test_zz1_terminal_in_gui() 1901 CheckCanRunGui 1902 1903 " Ignore the "failed to create input context" error. 1904 call test_ignore_error('E285:') 1905 1906 gui -f 1907 1908 call assert_equal(1, winnr('$')) 1909 let buf = Run_shell_in_terminal({'term_finish': 'close'}) 1910 call StopShellInTerminal(buf) 1911 call term_wait(buf) 1912 1913 " closing window wipes out the terminal buffer a with finished job 1914 call WaitForAssert({-> assert_equal(1, winnr('$'))}) 1915 call assert_equal("", bufname(buf)) 1916 1917 unlet g:job 1918endfunc 1919 1920func Test_zz2_terminal_guioptions_bang() 1921 CheckGui 1922 set guioptions+=! 1923 1924 let filename = 'Xtestscript' 1925 if has('win32') 1926 let filename .= '.bat' 1927 let prefix = '' 1928 let contents = ['@echo off', 'exit %1'] 1929 else 1930 let filename .= '.sh' 1931 let prefix = './' 1932 let contents = ['#!/bin/sh', 'exit $1'] 1933 endif 1934 call writefile(contents, filename) 1935 call setfperm(filename, 'rwxrwx---') 1936 1937 " Check if v:shell_error is equal to the exit status. 1938 let exitval = 0 1939 execute printf(':!%s%s %d', prefix, filename, exitval) 1940 call assert_equal(exitval, v:shell_error) 1941 1942 let exitval = 9 1943 execute printf(':!%s%s %d', prefix, filename, exitval) 1944 call assert_equal(exitval, v:shell_error) 1945 1946 set guioptions& 1947 call delete(filename) 1948endfunc 1949 1950func Test_terminal_hidden() 1951 CheckUnix 1952 1953 term ++hidden cat 1954 let bnr = bufnr('$') 1955 call assert_equal('terminal', getbufvar(bnr, '&buftype')) 1956 exe 'sbuf ' . bnr 1957 call assert_equal('terminal', &buftype) 1958 call term_sendkeys(bnr, "asdf\<CR>") 1959 call WaitForAssert({-> assert_match('asdf', term_getline(bnr, 2))}) 1960 call term_sendkeys(bnr, "\<C-D>") 1961 call WaitForAssert({-> assert_equal('finished', bnr->term_getstatus())}) 1962 bwipe! 1963endfunc 1964 1965func Test_terminal_switch_mode() 1966 term 1967 let bnr = bufnr('$') 1968 call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))}) 1969 call feedkeys("\<C-W>N", 'xt') 1970 call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))}) 1971 call feedkeys("A", 'xt') 1972 call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))}) 1973 call feedkeys("\<C-W>N", 'xt') 1974 call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))}) 1975 call feedkeys("I", 'xt') 1976 call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))}) 1977 call feedkeys("\<C-W>Nv", 'xt') 1978 call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))}) 1979 call feedkeys("I", 'xt') 1980 call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))}) 1981 call feedkeys("\<C-W>Nv", 'xt') 1982 call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))}) 1983 call feedkeys("A", 'xt') 1984 call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))}) 1985 bwipe! 1986endfunc 1987 1988func Test_terminal_normal_mode() 1989 CheckRunVimInTerminal 1990 1991 " Run Vim in a terminal and open a terminal window to run Vim in. 1992 let lines =<< trim END 1993 call setline(1, range(11111, 11122)) 1994 3 1995 END 1996 call writefile(lines, 'XtermNormal') 1997 let buf = RunVimInTerminal('-S XtermNormal', {'rows': 8}) 1998 call term_wait(buf) 1999 2000 call term_sendkeys(buf, "\<C-W>N") 2001 call term_sendkeys(buf, ":set number cursorline culopt=both\r") 2002 call VerifyScreenDump(buf, 'Test_terminal_normal_1', {}) 2003 2004 call term_sendkeys(buf, ":set culopt=number\r") 2005 call VerifyScreenDump(buf, 'Test_terminal_normal_2', {}) 2006 2007 call term_sendkeys(buf, ":set culopt=line\r") 2008 call VerifyScreenDump(buf, 'Test_terminal_normal_3', {}) 2009 2010 call term_sendkeys(buf, "a:q!\<CR>:q\<CR>:q\<CR>") 2011 call StopVimInTerminal(buf) 2012 call delete('XtermNormal') 2013endfunc 2014 2015func Test_terminal_hidden_and_close() 2016 CheckUnix 2017 2018 call assert_equal(1, winnr('$')) 2019 term ++hidden ++close ls 2020 let bnr = bufnr('$') 2021 call assert_equal('terminal', getbufvar(bnr, '&buftype')) 2022 call WaitForAssert({-> assert_false(bufexists(bnr))}) 2023 call assert_equal(1, winnr('$')) 2024endfunc 2025 2026func Test_terminal_does_not_truncate_last_newlines() 2027 " This test does not pass through ConPTY. 2028 if has('conpty') 2029 return 2030 endif 2031 let contents = [ 2032 \ [ 'One', '', 'X' ], 2033 \ [ 'Two', '', '' ], 2034 \ [ 'Three' ] + repeat([''], 30) 2035 \ ] 2036 2037 for c in contents 2038 call writefile(c, 'Xfile') 2039 if has('win32') 2040 term cmd /c type Xfile 2041 else 2042 term cat Xfile 2043 endif 2044 let bnr = bufnr('$') 2045 call assert_equal('terminal', getbufvar(bnr, '&buftype')) 2046 call WaitForAssert({-> assert_equal('finished', term_getstatus(bnr))}) 2047 sleep 100m 2048 call assert_equal(c, getline(1, line('$'))) 2049 quit 2050 endfor 2051 2052 call delete('Xfile') 2053endfunc 2054 2055func Test_terminal_no_job() 2056 if has('win32') 2057 let cmd = 'cmd /c ""' 2058 else 2059 CheckExecutable false 2060 let cmd = 'false' 2061 endif 2062 let term = term_start(cmd, {'term_finish': 'close'}) 2063 call WaitForAssert({-> assert_equal(v:null, term_getjob(term)) }) 2064endfunc 2065 2066func Test_term_getcursor() 2067 CheckUnix 2068 2069 let buf = Run_shell_in_terminal({}) 2070 2071 " Wait for the shell to display a prompt. 2072 call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) 2073 2074 " Hide the cursor. 2075 call term_sendkeys(buf, "echo -e '\\033[?25l'\r") 2076 call WaitForAssert({-> assert_equal(0, term_getcursor(buf)[2].visible)}) 2077 2078 " Show the cursor. 2079 call term_sendkeys(buf, "echo -e '\\033[?25h'\r") 2080 call WaitForAssert({-> assert_equal(1, buf->term_getcursor()[2].visible)}) 2081 2082 " Change color of cursor. 2083 call WaitForAssert({-> assert_equal('', term_getcursor(buf)[2].color)}) 2084 call term_sendkeys(buf, "echo -e '\\033]12;blue\\007'\r") 2085 call WaitForAssert({-> assert_equal('blue', term_getcursor(buf)[2].color)}) 2086 call term_sendkeys(buf, "echo -e '\\033]12;green\\007'\r") 2087 call WaitForAssert({-> assert_equal('green', term_getcursor(buf)[2].color)}) 2088 2089 " Make cursor a blinking block. 2090 call term_sendkeys(buf, "echo -e '\\033[1 q'\r") 2091 call WaitForAssert({-> assert_equal([1, 1], 2092 \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])}) 2093 2094 " Make cursor a steady block. 2095 call term_sendkeys(buf, "echo -e '\\033[2 q'\r") 2096 call WaitForAssert({-> assert_equal([0, 1], 2097 \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])}) 2098 2099 " Make cursor a blinking underline. 2100 call term_sendkeys(buf, "echo -e '\\033[3 q'\r") 2101 call WaitForAssert({-> assert_equal([1, 2], 2102 \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])}) 2103 2104 " Make cursor a steady underline. 2105 call term_sendkeys(buf, "echo -e '\\033[4 q'\r") 2106 call WaitForAssert({-> assert_equal([0, 2], 2107 \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])}) 2108 2109 " Make cursor a blinking vertical bar. 2110 call term_sendkeys(buf, "echo -e '\\033[5 q'\r") 2111 call WaitForAssert({-> assert_equal([1, 3], 2112 \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])}) 2113 2114 " Make cursor a steady vertical bar. 2115 call term_sendkeys(buf, "echo -e '\\033[6 q'\r") 2116 call WaitForAssert({-> assert_equal([0, 3], 2117 \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])}) 2118 2119 call StopShellInTerminal(buf) 2120endfunc 2121 2122func Test_term_gettitle() 2123 " term_gettitle() returns an empty string for a non-terminal buffer 2124 " and for a non-existing buffer. 2125 call assert_equal('', bufnr('%')->term_gettitle()) 2126 call assert_equal('', term_gettitle(bufnr('$') + 1)) 2127 2128 if !has('title') || &title == 0 || empty(&t_ts) 2129 throw "Skipped: can't get/set title" 2130 endif 2131 2132 let term = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile']) 2133 if has('autoservername') 2134 call WaitForAssert({-> assert_match('^\[No Name\] - VIM\d\+$', term_gettitle(term)) }) 2135 call term_sendkeys(term, ":e Xfoo\r") 2136 call WaitForAssert({-> assert_match('^Xfoo (.*[/\\]testdir) - VIM\d\+$', term_gettitle(term)) }) 2137 else 2138 call WaitForAssert({-> assert_equal('[No Name] - VIM', term_gettitle(term)) }) 2139 call term_sendkeys(term, ":e Xfoo\r") 2140 call WaitForAssert({-> assert_match('^Xfoo (.*[/\\]testdir) - VIM$', term_gettitle(term)) }) 2141 endif 2142 2143 call term_sendkeys(term, ":set titlestring=foo\r") 2144 call WaitForAssert({-> assert_equal('foo', term_gettitle(term)) }) 2145 2146 exe term . 'bwipe!' 2147endfunc 2148 2149" When drawing the statusline the cursor position may not have been updated 2150" yet. 2151" 1. create a terminal, make it show 2 lines 2152" 2. 0.5 sec later: leave terminal window, execute "i" 2153" 3. 0.5 sec later: clear terminal window, now it's 1 line 2154" 4. 0.5 sec later: redraw, including statusline (used to trigger bug) 2155" 4. 0.5 sec later: should be done, clean up 2156func Test_terminal_statusline() 2157 CheckUnix 2158 2159 set statusline=x 2160 terminal 2161 let tbuf = bufnr('') 2162 call term_sendkeys(tbuf, "clear; echo a; echo b; sleep 1; clear\n") 2163 call timer_start(500, { tid -> feedkeys("\<C-w>j", 'tx') }) 2164 call timer_start(1500, { tid -> feedkeys("\<C-l>", 'tx') }) 2165 au BufLeave * if &buftype == 'terminal' | silent! normal i | endif 2166 2167 sleep 2 2168 exe tbuf . 'bwipe!' 2169 au! BufLeave 2170 set statusline= 2171endfunc 2172 2173func Test_terminal_getwinpos() 2174 CheckRunVimInTerminal 2175 2176 " split, go to the bottom-right window 2177 split 2178 wincmd j 2179 set splitright 2180 2181 call writefile([ 2182 \ 'echo getwinpos()', 2183 \ ], 'XTest_getwinpos') 2184 let buf = RunVimInTerminal('-S XTest_getwinpos', {'cols': 60}) 2185 call term_wait(buf) 2186 2187 " Find the output of getwinpos() in the bottom line. 2188 let rows = term_getsize(buf)[0] 2189 call WaitForAssert({-> assert_match('\[\d\+, \d\+\]', term_getline(buf, rows))}) 2190 let line = term_getline(buf, rows) 2191 let xpos = str2nr(substitute(line, '\[\(\d\+\), \d\+\]', '\1', '')) 2192 let ypos = str2nr(substitute(line, '\[\d\+, \(\d\+\)\]', '\1', '')) 2193 2194 " Position must be bigger than the getwinpos() result of Vim itself. 2195 " The calculation in the console assumes a 10 x 7 character cell. 2196 " In the GUI it can be more, let's assume a 20 x 14 cell. 2197 " And then add 100 / 200 tolerance. 2198 let [xroot, yroot] = getwinpos() 2199 let winpos = 50->getwinpos() 2200 call assert_equal(xroot, winpos[0]) 2201 call assert_equal(yroot, winpos[1]) 2202 let [winrow, wincol] = win_screenpos('.') 2203 let xoff = wincol * (has('gui_running') ? 14 : 7) + 100 2204 let yoff = winrow * (has('gui_running') ? 20 : 10) + 200 2205 call assert_inrange(xroot + 2, xroot + xoff, xpos) 2206 call assert_inrange(yroot + 2, yroot + yoff, ypos) 2207 2208 call term_wait(buf) 2209 call term_sendkeys(buf, ":q\<CR>") 2210 call StopVimInTerminal(buf) 2211 call delete('XTest_getwinpos') 2212 exe buf . 'bwipe!' 2213 set splitright& 2214 only! 2215endfunc 2216 2217func Test_terminal_altscreen() 2218 " somehow doesn't work on MS-Windows 2219 CheckUnix 2220 let cmd = "cat Xtext\<CR>" 2221 2222 let buf = term_start(&shell, {}) 2223 call writefile(["\<Esc>[?1047h"], 'Xtext') 2224 call term_sendkeys(buf, cmd) 2225 call WaitForAssert({-> assert_equal(1, term_getaltscreen(buf))}) 2226 2227 call writefile(["\<Esc>[?1047l"], 'Xtext') 2228 call term_sendkeys(buf, cmd) 2229 call WaitForAssert({-> assert_equal(0, term_getaltscreen(buf))}) 2230 2231 call term_sendkeys(buf, "exit\r") 2232 exe buf . "bwipe!" 2233 call delete('Xtext') 2234endfunc 2235 2236func Test_terminal_shell_option() 2237 if has('unix') 2238 " exec is a shell builtin command, should fail without a shell. 2239 term exec ls runtest.vim 2240 call WaitForAssert({-> assert_match('job failed', term_getline(bufnr(), 1))}) 2241 bwipe! 2242 2243 term ++shell exec ls runtest.vim 2244 call WaitForAssert({-> assert_match('runtest.vim', term_getline(bufnr(), 1))}) 2245 bwipe! 2246 elseif has('win32') 2247 " dir is a shell builtin command, should fail without a shell. 2248 try 2249 term dir /b runtest.vim 2250 call WaitForAssert({-> assert_match('job failed\|cannot access .*: No such file or directory', term_getline(bufnr(), 1))}) 2251 catch /CreateProcess/ 2252 " ignore 2253 endtry 2254 bwipe! 2255 2256 term ++shell dir /b runtest.vim 2257 call WaitForAssert({-> assert_match('runtest.vim', term_getline(bufnr(), 1))}) 2258 bwipe! 2259 endif 2260endfunc 2261 2262func Test_terminal_setapi_and_call() 2263 CheckRunVimInTerminal 2264 2265 call WriteApiCall('Tapi_TryThis') 2266 call ch_logfile('Xlog', 'w') 2267 2268 unlet! g:called_bufnum 2269 unlet! g:called_arg 2270 2271 let buf = RunVimInTerminal('-S Xscript', {'term_api': ''}) 2272 call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))}) 2273 call assert_false(exists('g:called_bufnum')) 2274 call assert_false(exists('g:called_arg')) 2275 2276 eval buf->term_setapi('Tapi_') 2277 call term_sendkeys(buf, ":set notitle\<CR>") 2278 call term_sendkeys(buf, ":source Xscript\<CR>") 2279 call WaitFor({-> exists('g:called_bufnum')}) 2280 call assert_equal(buf, g:called_bufnum) 2281 call assert_equal(['hello', 123], g:called_arg) 2282 2283 call StopVimInTerminal(buf) 2284 2285 call delete('Xscript') 2286 call ch_logfile('') 2287 call delete('Xlog') 2288 unlet! g:called_bufnum 2289 unlet! g:called_arg 2290endfunc 2291 2292func Test_terminal_api_arg() 2293 CheckRunVimInTerminal 2294 2295 call WriteApiCall('Tapi_TryThis') 2296 call ch_logfile('Xlog', 'w') 2297 2298 unlet! g:called_bufnum 2299 unlet! g:called_arg 2300 2301 execute 'term ++api= ' .. GetVimCommandCleanTerm() .. '-S Xscript' 2302 let buf = bufnr('%') 2303 call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))}) 2304 call assert_false(exists('g:called_bufnum')) 2305 call assert_false(exists('g:called_arg')) 2306 2307 call StopVimInTerminal(buf) 2308 2309 call ch_logfile('Xlog', 'w') 2310 2311 execute 'term ++api=Tapi_ ' .. GetVimCommandCleanTerm() .. '-S Xscript' 2312 let buf = bufnr('%') 2313 call WaitFor({-> exists('g:called_bufnum')}) 2314 call assert_equal(buf, g:called_bufnum) 2315 call assert_equal(['hello', 123], g:called_arg) 2316 2317 call StopVimInTerminal(buf) 2318 2319 call delete('Xscript') 2320 call ch_logfile('') 2321 call delete('Xlog') 2322 unlet! g:called_bufnum 2323 unlet! g:called_arg 2324endfunc 2325 2326func Test_terminal_in_popup() 2327 CheckRunVimInTerminal 2328 2329 let text =<< trim END 2330 some text 2331 to edit 2332 in a popup window 2333 END 2334 call writefile(text, 'Xtext') 2335 let cmd = GetVimCommandCleanTerm() 2336 let lines = [ 2337 \ 'set t_u7=', 2338 \ 'call setline(1, range(20))', 2339 \ 'hi PopTerm ctermbg=grey', 2340 \ 'func OpenTerm(setColor)', 2341 \ " let s:buf = term_start('" .. cmd .. " Xtext', #{hidden: 1, term_finish: 'close'})", 2342 \ ' let s:winid = popup_create(s:buf, #{minwidth: 45, minheight: 7, border: [], drag: 1, resize: 1})', 2343 \ ' if a:setColor', 2344 \ ' call win_execute(s:winid, "set wincolor=PopTerm")', 2345 \ ' endif', 2346 \ 'endfunc', 2347 \ 'call OpenTerm(0)', 2348 \ 'func HidePopup()', 2349 \ ' call popup_hide(s:winid)', 2350 \ 'endfunc', 2351 \ 'func ClosePopup()', 2352 \ ' call popup_close(s:winid)', 2353 \ 'endfunc', 2354 \ 'func ReopenPopup()', 2355 \ ' call popup_create(s:buf, #{minwidth: 40, minheight: 6, border: []})', 2356 \ 'endfunc', 2357 \ 'sleep 10m', 2358 \ 'redraw', 2359 \ 'echo getwinvar(s:winid, "&buftype") win_gettype(s:winid)', 2360 \ ] 2361 call writefile(lines, 'XtermPopup') 2362 let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15}) 2363 call term_wait(buf, 100) 2364 call term_sendkeys(buf, ":\<CR>") 2365 call VerifyScreenDump(buf, 'Test_terminal_popup_1', {}) 2366 2367 call term_sendkeys(buf, ":q\<CR>") 2368 call VerifyScreenDump(buf, 'Test_terminal_popup_2', {}) 2369 2370 call term_sendkeys(buf, ":call OpenTerm(1)\<CR>") 2371 call term_sendkeys(buf, ":set hlsearch\<CR>") 2372 call term_sendkeys(buf, "/edit\<CR>") 2373 call VerifyScreenDump(buf, 'Test_terminal_popup_3', {}) 2374 2375 call term_sendkeys(buf, "\<C-W>:call HidePopup()\<CR>") 2376 call VerifyScreenDump(buf, 'Test_terminal_popup_4', {}) 2377 call term_sendkeys(buf, "\<CR>") 2378 call term_wait(buf, 100) 2379 2380 call term_sendkeys(buf, "\<C-W>:call ClosePopup()\<CR>") 2381 call VerifyScreenDump(buf, 'Test_terminal_popup_5', {}) 2382 2383 call term_sendkeys(buf, "\<C-W>:call ReopenPopup()\<CR>") 2384 call VerifyScreenDump(buf, 'Test_terminal_popup_6', {}) 2385 call term_wait(buf, 100) 2386 2387 call term_sendkeys(buf, ":q\<CR>") 2388 call term_wait(buf, 100) " wait for terminal to vanish 2389 2390 call StopVimInTerminal(buf) 2391 call delete('XtermPopup') 2392endfunc 2393 2394func Test_issue_5607() 2395 let wincount = winnr('$') 2396 exe 'terminal' &shell &shellcmdflag 'exit' 2397 let job = term_getjob(bufnr()) 2398 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 2399 2400 let old_wincolor = &wincolor 2401 try 2402 set wincolor= 2403 finally 2404 let &wincolor = old_wincolor 2405 bw! 2406 endtry 2407endfunc 2408 2409func Test_hidden_terminal() 2410 let buf = term_start(&shell, #{hidden: 1}) 2411 call assert_equal('', bufname('^$')) 2412 call StopShellInTerminal(buf) 2413endfunc 2414