1" Tests for the terminal window.
2" This is split in two, because it can take a lot of time.
3" See test_terminal2.vim and test_terminal3.vim for further tests.
4
5source check.vim
6CheckFeature terminal
7
8source shared.vim
9source screendump.vim
10source mouse.vim
11source term_util.vim
12
13let s:python = PythonProg()
14let $PROMPT_COMMAND=''
15
16func Test_terminal_basic()
17  au TerminalOpen * let b:done = 'yes'
18  let buf = Run_shell_in_terminal({})
19
20  call assert_equal('t', mode())
21  call assert_equal('yes', b:done)
22  call assert_match('%aR[^\n]*running]', execute('ls'))
23  call assert_match('%aR[^\n]*running]', execute('ls R'))
24  call assert_notmatch('%[^\n]*running]', execute('ls F'))
25  call assert_notmatch('%[^\n]*running]', execute('ls ?'))
26  call assert_fails('set modifiable', 'E946:')
27
28  call StopShellInTerminal(buf)
29  call TermWait(buf)
30  call assert_equal('n', mode())
31  call assert_match('%aF[^\n]*finished]', execute('ls'))
32  call assert_match('%aF[^\n]*finished]', execute('ls F'))
33  call assert_notmatch('%[^\n]*finished]', execute('ls R'))
34  call assert_notmatch('%[^\n]*finished]', execute('ls ?'))
35
36  " closing window wipes out the terminal buffer a with finished job
37  close
38  call assert_equal("", bufname(buf))
39
40  au! TerminalOpen
41  unlet g:job
42endfunc
43
44func Test_terminal_TerminalWinOpen()
45  au TerminalWinOpen * let b:done = 'yes'
46  let buf = Run_shell_in_terminal({})
47  call assert_equal('yes', b:done)
48  call StopShellInTerminal(buf)
49  " closing window wipes out the terminal buffer with the finished job
50  close
51
52  if has("unix")
53    terminal ++hidden ++open sleep 1
54    sleep 1
55    call assert_fails("echo b:done", 'E121:')
56  endif
57
58  au! TerminalWinOpen
59endfunc
60
61func Test_terminal_make_change()
62  let buf = Run_shell_in_terminal({})
63  call StopShellInTerminal(buf)
64  call TermWait(buf)
65
66  setlocal modifiable
67  exe "normal Axxx\<Esc>"
68  call assert_fails(buf . 'bwipe', ['E89:', 'E517'])
69  undo
70
71  exe buf . 'bwipe'
72  unlet g:job
73endfunc
74
75func Test_terminal_paste_register()
76  let @" = "text to paste"
77
78  let buf = Run_shell_in_terminal({})
79  " Wait for the shell to display a prompt
80  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
81
82  call feedkeys("echo \<C-W>\"\" \<C-W>\"=37 + 5\<CR>\<CR>", 'xt')
83  call WaitForAssert({-> assert_match("echo text to paste 42$", getline(1))})
84  call WaitForAssert({-> assert_equal('text to paste 42',       2->getline())})
85
86  exe buf . 'bwipe!'
87  unlet g:job
88endfunc
89
90func Test_terminal_wipe_buffer()
91  let buf = Run_shell_in_terminal({})
92  call assert_fails(buf . 'bwipe', ['E89', 'E517'])
93  exe buf . 'bwipe!'
94  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
95  call assert_equal("", bufname(buf))
96
97  unlet g:job
98endfunc
99
100func Test_terminal_split_quit()
101  let buf = Run_shell_in_terminal({})
102  call TermWait(buf)
103  split
104  quit!
105  call TermWait(buf)
106  sleep 50m
107  call assert_equal('run', job_status(g:job))
108
109  quit!
110  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
111
112  exe buf . 'bwipe'
113  unlet g:job
114endfunc
115
116func Test_terminal_hide_buffer()
117  let buf = Run_shell_in_terminal({})
118  setlocal bufhidden=hide
119  quit
120  for nr in range(1, winnr('$'))
121    call assert_notequal(winbufnr(nr), buf)
122  endfor
123  call assert_true(bufloaded(buf))
124  call assert_true(buflisted(buf))
125
126  exe 'split ' . buf . 'buf'
127  call StopShellInTerminal(buf)
128  exe buf . 'bwipe'
129
130  unlet g:job
131endfunc
132
133func s:Nasty_exit_cb(job, st)
134  exe g:buf . 'bwipe!'
135  let g:buf = 0
136endfunc
137
138func Get_cat_123_cmd()
139  if has('win32')
140    if !has('conpty')
141      return 'cmd /c "cls && color 2 && echo 123"'
142    else
143      " When clearing twice, extra sequence is not output.
144      return 'cmd /c "cls && cls && color 2 && echo 123"'
145    endif
146  else
147    call writefile(["\<Esc>[32m123"], 'Xtext')
148    return "cat Xtext"
149  endif
150endfunc
151
152func Test_terminal_nasty_cb()
153  let cmd = Get_cat_123_cmd()
154  let g:buf = term_start(cmd, {'exit_cb': function('s:Nasty_exit_cb')})
155  let g:job = term_getjob(g:buf)
156
157  call WaitForAssert({-> assert_equal("dead", job_status(g:job))})
158  call WaitForAssert({-> assert_equal(0, g:buf)})
159  unlet g:job
160  unlet g:buf
161  call delete('Xtext')
162endfunc
163
164func Check_123(buf)
165  let l = term_scrape(a:buf, 0)
166  call assert_true(len(l) == 0)
167  let l = term_scrape(a:buf, 999)
168  call assert_true(len(l) == 0)
169  let l = a:buf->term_scrape(1)
170  call assert_true(len(l) > 0)
171  call assert_equal('1', l[0].chars)
172  call assert_equal('2', l[1].chars)
173  call assert_equal('3', l[2].chars)
174  call assert_equal('#00e000', l[0].fg)
175  call assert_equal(0, term_getattr(l[0].attr, 'bold'))
176  call assert_equal(0, l[0].attr->term_getattr('italic'))
177  if has('win32')
178    " On Windows 'background' always defaults to dark, even though the terminal
179    " may use a light background.  Therefore accept both white and black.
180    call assert_match('#ffffff\|#000000', l[0].bg)
181  else
182    if &background == 'light'
183      call assert_equal('#ffffff', l[0].bg)
184    else
185      call assert_equal('#000000', l[0].bg)
186    endif
187  endif
188
189  let l = term_getline(a:buf, -1)
190  call assert_equal('', l)
191  let l = term_getline(a:buf, 0)
192  call assert_equal('', l)
193  let l = term_getline(a:buf, 999)
194  call assert_equal('', l)
195  let l = term_getline(a:buf, 1)
196  call assert_equal('123', l)
197endfunc
198
199func Test_terminal_scrape_123()
200  let cmd = Get_cat_123_cmd()
201  let buf = term_start(cmd)
202
203  let termlist = term_list()
204  call assert_equal(1, len(termlist))
205  call assert_equal(buf, termlist[0])
206
207  " Nothing happens with invalid buffer number
208  call term_wait(1234)
209
210  call TermWait(buf)
211  " On MS-Windows we first get a startup message of two lines, wait for the
212  " "cls" to happen, after that we have one line with three characters.
213  call WaitForAssert({-> assert_equal(3, len(term_scrape(buf, 1)))})
214  call Check_123(buf)
215
216  " Must still work after the job ended.
217  let job = term_getjob(buf)
218  call WaitForAssert({-> assert_equal("dead", job_status(job))})
219  call TermWait(buf)
220  call Check_123(buf)
221
222  exe buf . 'bwipe'
223  call delete('Xtext')
224endfunc
225
226func Test_terminal_scrape_multibyte()
227  call writefile(["léttまrs"], 'Xtext')
228  if has('win32')
229    " Run cmd with UTF-8 codepage to make the type command print the expected
230    " multibyte characters.
231    let buf = term_start("cmd /K chcp 65001")
232    call term_sendkeys(buf, "type Xtext\<CR>")
233    eval buf->term_sendkeys("exit\<CR>")
234    let line = 4
235  else
236    let buf = term_start("cat Xtext")
237    let line = 1
238  endif
239
240  call WaitFor({-> len(term_scrape(buf, line)) >= 7 && term_scrape(buf, line)[0].chars == "l"})
241  let l = term_scrape(buf, line)
242  call assert_true(len(l) >= 7)
243  call assert_equal('l', l[0].chars)
244  call assert_equal('é', l[1].chars)
245  call assert_equal(1, l[1].width)
246  call assert_equal('t', l[2].chars)
247  call assert_equal('t', l[3].chars)
248  call assert_equal('ま', l[4].chars)
249  call assert_equal(2, l[4].width)
250  call assert_equal('r', l[5].chars)
251  call assert_equal('s', l[6].chars)
252
253  let job = term_getjob(buf)
254  call WaitForAssert({-> assert_equal("dead", job_status(job))})
255  call TermWait(buf)
256
257  exe buf . 'bwipe'
258  call delete('Xtext')
259endfunc
260
261func Test_terminal_one_column()
262  " This creates a terminal, displays a double-wide character and makes the
263  " window one column wide.  This used to cause a crash.
264  let width = &columns
265  botright vert term
266  let buf = bufnr('$')
267  call term_wait(buf, 100)
268  exe "set columns=" .. (width / 2)
269  redraw
270  call term_sendkeys(buf, "キ")
271  call term_wait(buf, 10)
272  exe "set columns=" .. width
273  exe buf . 'bwipe!'
274endfunc
275
276func Test_terminal_scroll()
277  call writefile(range(1, 200), 'Xtext')
278  if has('win32')
279    let cmd = 'cmd /c "type Xtext"'
280  else
281    let cmd = "cat Xtext"
282  endif
283  let buf = term_start(cmd)
284
285  let job = term_getjob(buf)
286  call WaitForAssert({-> assert_equal("dead", job_status(job))})
287  call TermWait(buf)
288
289  " wait until the scrolling stops
290  while 1
291    let scrolled = buf->term_getscrolled()
292    sleep 20m
293    if scrolled == buf->term_getscrolled()
294      break
295    endif
296  endwhile
297
298  call assert_equal('1', getline(1))
299  call assert_equal('1', term_getline(buf, 1 - scrolled))
300  call assert_equal('49', getline(49))
301  call assert_equal('49', term_getline(buf, 49 - scrolled))
302  call assert_equal('200', getline(200))
303  call assert_equal('200', term_getline(buf, 200 - scrolled))
304
305  exe buf . 'bwipe'
306  call delete('Xtext')
307endfunc
308
309func Test_terminal_scrollback()
310  let buf = Run_shell_in_terminal({'term_rows': 15})
311  set termwinscroll=100
312  call writefile(range(150), 'Xtext')
313  if has('win32')
314    call term_sendkeys(buf, "type Xtext\<CR>")
315  else
316    call term_sendkeys(buf, "cat Xtext\<CR>")
317  endif
318  let rows = term_getsize(buf)[0]
319  " On MS-Windows there is an empty line, check both last line and above it.
320  call WaitForAssert({-> assert_match( '149', term_getline(buf, rows - 1) . term_getline(buf, rows - 2))})
321  let lines = line('$')
322  call assert_inrange(91, 100, lines)
323
324  call StopShellInTerminal(buf)
325  call TermWait(buf)
326  exe buf . 'bwipe'
327  set termwinscroll&
328  call delete('Xtext')
329endfunc
330
331func Test_terminal_postponed_scrollback()
332  " tail -f only works on Unix
333  CheckUnix
334
335  call writefile(range(50), 'Xtext')
336  call writefile([
337	\ 'set shell=/bin/sh noruler',
338	\ 'terminal',
339	\ 'sleep 200m',
340	\ 'call feedkeys("tail -n 100 -f Xtext\<CR>", "xt")',
341	\ 'sleep 100m',
342	\ 'call feedkeys("\<C-W>N", "xt")',
343	\ ], 'XTest_postponed')
344  let buf = RunVimInTerminal('-S XTest_postponed', {})
345  " Check that the Xtext lines are displayed and in Terminal-Normal mode
346  call VerifyScreenDump(buf, 'Test_terminal_scrollback_1', {})
347
348  silent !echo 'one more line' >>Xtext
349  " Screen will not change, move cursor to get a different dump
350  call term_sendkeys(buf, "k")
351  call VerifyScreenDump(buf, 'Test_terminal_scrollback_2', {})
352
353  " Back to Terminal-Job mode, text will scroll and show the extra line.
354  call term_sendkeys(buf, "a")
355  call VerifyScreenDump(buf, 'Test_terminal_scrollback_3', {})
356
357  " stop "tail -f"
358  call term_sendkeys(buf, "\<C-C>")
359  call TermWait(buf, 25)
360  " stop shell
361  call term_sendkeys(buf, "exit\<CR>")
362  call TermWait(buf, 50)
363  " close terminal window
364  let tsk_ret = term_sendkeys(buf, ":q\<CR>")
365
366  " check type of term_sendkeys() return value
367  echo type(tsk_ret)
368
369  call StopVimInTerminal(buf)
370  call delete('XTest_postponed')
371  call delete('Xtext')
372endfunc
373
374" Run diff on two dumps with different size.
375func Test_terminal_dumpdiff_size()
376  call assert_equal(1, winnr('$'))
377  call term_dumpdiff('dumps/Test_incsearch_search_01.dump', 'dumps/Test_popup_command_01.dump')
378  call assert_equal(2, winnr('$'))
379  call assert_match('Test_incsearch_search_01.dump', getline(10))
380  call assert_match('      +++++$', getline(11))
381  call assert_match('Test_popup_command_01.dump', getline(31))
382  call assert_equal(repeat('+', 75), getline(30))
383  quit
384endfunc
385
386func Test_terminal_size()
387  let cmd = Get_cat_123_cmd()
388
389  exe 'terminal ++rows=5 ' . cmd
390  let size = term_getsize('')
391  bwipe!
392  call assert_equal(5, size[0])
393
394  call term_start(cmd, {'term_rows': 6})
395  let size = term_getsize('')
396  bwipe!
397  call assert_equal(6, size[0])
398
399  vsplit
400  exe 'terminal ++rows=5 ++cols=33 ' . cmd
401  call assert_equal([5, 33], ''->term_getsize())
402
403  call term_setsize('', 6, 0)
404  call assert_equal([6, 33], term_getsize(''))
405
406  eval ''->term_setsize(0, 35)
407  call assert_equal([6, 35], term_getsize(''))
408
409  call term_setsize('', 7, 30)
410  call assert_equal([7, 30], term_getsize(''))
411
412  bwipe!
413  call assert_fails("call term_setsize('', 7, 30)", "E955:")
414
415  call term_start(cmd, {'term_rows': 6, 'term_cols': 36})
416  let size = term_getsize('')
417  bwipe!
418  call assert_equal([6, 36], size)
419
420  exe 'vertical terminal ++cols=20 ' . cmd
421  let size = term_getsize('')
422  bwipe!
423  call assert_equal(20, size[1])
424
425  eval cmd->term_start({'vertical': 1, 'term_cols': 26})
426  let size = term_getsize('')
427  bwipe!
428  call assert_equal(26, size[1])
429
430  split
431  exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd
432  let size = term_getsize('')
433  bwipe!
434  call assert_equal([6, 20], size)
435
436  call term_start(cmd, {'vertical': 1, 'term_rows': 7, 'term_cols': 27})
437  let size = term_getsize('')
438  bwipe!
439  call assert_equal([7, 27], size)
440
441  call delete('Xtext')
442endfunc
443
444func Test_terminal_curwin()
445  let cmd = Get_cat_123_cmd()
446  call assert_equal(1, winnr('$'))
447
448  split Xdummy
449  call setline(1, 'dummy')
450  write
451  call assert_equal(1, getbufinfo('Xdummy')[0].loaded)
452  exe 'terminal ++curwin ' . cmd
453  call assert_equal(2, winnr('$'))
454  call assert_equal(0, getbufinfo('Xdummy')[0].loaded)
455  bwipe!
456
457  split Xdummy
458  call term_start(cmd, {'curwin': 1})
459  call assert_equal(2, winnr('$'))
460  bwipe!
461
462  split Xdummy
463  call setline(1, 'change')
464  call assert_fails('terminal ++curwin ' . cmd, 'E37:')
465  call assert_equal(2, winnr('$'))
466  exe 'terminal! ++curwin ' . cmd
467  call assert_equal(2, winnr('$'))
468  bwipe!
469
470  split Xdummy
471  call setline(1, 'change')
472  call assert_fails("call term_start(cmd, {'curwin': 1})", 'E37:')
473  call assert_equal(2, winnr('$'))
474  bwipe!
475
476  split Xdummy
477  bwipe!
478  call delete('Xtext')
479  call delete('Xdummy')
480endfunc
481
482func s:get_sleep_cmd()
483  if s:python != ''
484    let cmd = s:python . " test_short_sleep.py"
485    " 500 was not enough for Travis
486    let waittime = 900
487  else
488    echo 'This will take five seconds...'
489    let waittime = 2000
490    if has('win32')
491      let cmd = $windir . '\system32\timeout.exe 1'
492    else
493      let cmd = 'sleep 1'
494    endif
495  endif
496  return [cmd, waittime]
497endfunc
498
499func Test_terminal_finish_open_close()
500  call assert_equal(1, winnr('$'))
501
502  let [cmd, waittime] = s:get_sleep_cmd()
503
504  " shell terminal closes automatically
505  terminal
506  let buf = bufnr('%')
507  call assert_equal(2, winnr('$'))
508  " Wait for the shell to display a prompt
509  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
510  call StopShellInTerminal(buf)
511  call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
512
513  " shell terminal that does not close automatically
514  terminal ++noclose
515  let buf = bufnr('%')
516  call assert_equal(2, winnr('$'))
517  " Wait for the shell to display a prompt
518  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
519  call StopShellInTerminal(buf)
520  call assert_equal(2, winnr('$'))
521  quit
522  call assert_equal(1, winnr('$'))
523
524  exe 'terminal ++close ' . cmd
525  call assert_equal(2, winnr('$'))
526  wincmd p
527  call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
528
529  call term_start(cmd, {'term_finish': 'close'})
530  call assert_equal(2, winnr('$'))
531  wincmd p
532  call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
533  call assert_equal(1, winnr('$'))
534
535  exe 'terminal ++open ' . cmd
536  close!
537  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
538  bwipe
539
540  call term_start(cmd, {'term_finish': 'open'})
541  close!
542  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
543  bwipe
544
545  exe 'terminal ++hidden ++open ' . cmd
546  call assert_equal(1, winnr('$'))
547  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
548  bwipe
549
550  call term_start(cmd, {'term_finish': 'open', 'hidden': 1})
551  call assert_equal(1, winnr('$'))
552  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
553  bwipe
554
555  call assert_fails("call term_start(cmd, {'term_opencmd': 'open'})", 'E475:')
556  call assert_fails("call term_start(cmd, {'term_opencmd': 'split %x'})", 'E475:')
557  call assert_fails("call term_start(cmd, {'term_opencmd': 'split %d and %s'})", 'E475:')
558  call assert_fails("call term_start(cmd, {'term_opencmd': 'split % and %d'})", 'E475:')
559
560  call term_start(cmd, {'term_finish': 'open', 'term_opencmd': '4split | buffer %d'})
561  close!
562  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
563  call assert_equal(4, winheight(0))
564  bwipe
565endfunc
566
567func Test_terminal_cwd()
568  if has('win32')
569    let cmd = 'cmd /c cd'
570  else
571    CheckExecutable pwd
572    let cmd = 'pwd'
573  endif
574  call mkdir('Xdir')
575  let buf = term_start(cmd, {'cwd': 'Xdir'})
576  call WaitForAssert({-> assert_equal('Xdir', fnamemodify(getline(1), ":t"))})
577
578  exe buf . 'bwipe'
579  call delete('Xdir', 'rf')
580endfunc
581
582func Test_terminal_cwd_failure()
583  " Case 1: Provided directory is not actually a directory.  Attempt to make
584  " the file executable as well.
585  call writefile([], 'Xfile')
586  call setfperm('Xfile', 'rwx------')
587  call assert_fails("call term_start(&shell, {'cwd': 'Xfile'})", 'E475:')
588  call delete('Xfile')
589
590  " Case 2: Directory does not exist.
591  call assert_fails("call term_start(&shell, {'cwd': 'Xdir'})", 'E475:')
592
593  " Case 3: Directory exists but is not accessible.
594  " Skip this for root, it will be accessible anyway.
595  if !IsRoot()
596    call mkdir('XdirNoAccess', '', '0600')
597    " return early if the directory permissions could not be set properly
598    if getfperm('XdirNoAccess')[2] == 'x'
599      call delete('XdirNoAccess', 'rf')
600      return
601    endif
602    call assert_fails("call term_start(&shell, {'cwd': 'XdirNoAccess'})", 'E475:')
603    call delete('XdirNoAccess', 'rf')
604  endif
605endfunc
606
607func Test_terminal_servername()
608  if !has('clientserver')
609    return
610  endif
611  call s:test_environment("VIM_SERVERNAME", v:servername)
612endfunc
613
614func Test_terminal_version()
615  call s:test_environment("VIM_TERMINAL", string(v:version))
616endfunc
617
618func s:test_environment(name, value)
619  let buf = Run_shell_in_terminal({})
620  " Wait for the shell to display a prompt
621  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
622  if has('win32')
623    call term_sendkeys(buf, "echo %" . a:name . "%\r")
624  else
625    call term_sendkeys(buf, "echo $" . a:name . "\r")
626  endif
627  call TermWait(buf)
628  call StopShellInTerminal(buf)
629  call WaitForAssert({-> assert_equal(a:value, getline(2))})
630
631  exe buf . 'bwipe'
632  unlet buf
633endfunc
634
635func Test_terminal_env()
636  let buf = Run_shell_in_terminal({'env': {'TESTENV': 'correct'}})
637  " Wait for the shell to display a prompt
638  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
639  if has('win32')
640    call term_sendkeys(buf, "echo %TESTENV%\r")
641  else
642    call term_sendkeys(buf, "echo $TESTENV\r")
643  endif
644  eval buf->TermWait()
645  call StopShellInTerminal(buf)
646  call WaitForAssert({-> assert_equal('correct', getline(2))})
647
648  exe buf . 'bwipe'
649endfunc
650
651func Test_terminal_list_args()
652  let buf = term_start([&shell, &shellcmdflag, 'echo "123"'])
653  call assert_fails(buf . 'bwipe', ['E89', 'E517'])
654  exe buf . 'bwipe!'
655  call assert_equal("", bufname(buf))
656endfunction
657
658func Test_terminal_noblock()
659  let buf = term_start(&shell)
660  let wait_time = 5000
661  let letters = 'abcdefghijklmnopqrstuvwxyz'
662  if has('bsd') || has('mac') || has('sun')
663    " The shell or something else has a problem dealing with more than 1000
664    " characters at the same time.  It's very slow too.
665    let len = 1000
666    let wait_time = 15000
667    let letters = 'abcdefghijklm'
668  " NPFS is used in Windows, nonblocking mode does not work properly.
669  elseif has('win32')
670    let len = 1
671  else
672    let len = 5000
673  endif
674
675  " Send a lot of text lines, should be buffered properly.
676  for c in split(letters, '\zs')
677    call term_sendkeys(buf, 'echo ' . repeat(c, len) . "\<cr>")
678  endfor
679  call term_sendkeys(buf, "echo done\<cr>")
680
681  " On MS-Windows there is an extra empty line below "done".  Find "done" in
682  " the last-but-one or the last-but-two line.
683  let lnum = term_getsize(buf)[0] - 1
684  call WaitForAssert({-> assert_match('done', term_getline(buf, lnum - 1) .. '//' .. term_getline(buf, lnum))}, wait_time)
685  let line = term_getline(buf, lnum)
686  if line !~ 'done'
687    let line = term_getline(buf, lnum - 1)
688  endif
689  call assert_match('done', line)
690
691  let g:job = term_getjob(buf)
692  call StopShellInTerminal(buf)
693  call TermWait(buf)
694  unlet g:job
695  bwipe
696endfunc
697
698func Test_terminal_write_stdin()
699  " TODO: enable once writing to stdin works on MS-Windows
700  CheckNotMSWindows
701  CheckExecutable wc
702
703  call setline(1, ['one', 'two', 'three'])
704  %term wc
705  call WaitForAssert({-> assert_match('3', getline("$"))})
706  let nrs = split(getline('$'))
707  call assert_equal(['3', '3', '14'], nrs)
708  %bwipe!
709
710  call setline(1, ['one', 'two', 'three', 'four'])
711  2,3term wc
712  call WaitForAssert({-> assert_match('2', getline("$"))})
713  let nrs = split(getline('$'))
714  call assert_equal(['2', '2', '10'], nrs)
715  %bwipe!
716endfunc
717
718func Test_terminal_eof_arg()
719  call CheckPython(s:python)
720
721  call setline(1, ['print("hello")'])
722  exe '1term ++eof=exit(123) ' .. s:python
723  " MS-Windows echoes the input, Unix doesn't.
724  if has('win32')
725    call WaitFor({-> getline('$') =~ 'exit(123)'})
726    call assert_equal('hello', getline(line('$') - 1))
727  else
728    call WaitFor({-> getline('$') =~ 'hello'})
729    call assert_equal('hello', getline('$'))
730  endif
731  call assert_equal(123, bufnr()->term_getjob()->job_info().exitval)
732  %bwipe!
733endfunc
734
735func Test_terminal_eof_arg_win32_ctrl_z()
736  CheckMSWindows
737  call CheckPython(s:python)
738
739  call setline(1, ['print("hello")'])
740  exe '1term ++eof=<C-Z> ' .. s:python
741  call WaitForAssert({-> assert_match('\^Z', getline(line('$') - 1))})
742  call assert_match('\^Z', getline(line('$') - 1))
743  %bwipe!
744endfunc
745
746func Test_terminal_duplicate_eof_arg()
747  call CheckPython(s:python)
748
749  " Check the last specified ++eof arg is used and should not memory leak.
750  new
751  call setline(1, ['print("hello")'])
752  exe '1term ++eof=<C-Z> ++eof=exit(123) ' .. s:python
753  " MS-Windows echoes the input, Unix doesn't.
754  if has('win32')
755    call WaitFor({-> getline('$') =~ 'exit(123)'})
756    call assert_equal('hello', getline(line('$') - 1))
757  else
758    call WaitFor({-> getline('$') =~ 'hello'})
759    call assert_equal('hello', getline('$'))
760  endif
761  call assert_equal(123, bufnr()->term_getjob()->job_info().exitval)
762  %bwipe!
763endfunc
764
765func Test_terminal_no_cmd()
766  let buf = term_start('NONE', {})
767  call assert_notequal(0, buf)
768
769  let pty = job_info(term_getjob(buf))['tty_out']
770  call assert_notequal('', pty)
771  if has('gui_running') && !has('win32')
772    " In the GUI job_start() doesn't work, it does not read from the pty.
773    call system('echo "look here" > ' . pty)
774  else
775    " Otherwise using a job works on all systems.
776    call job_start([&shell, &shellcmdflag, 'echo "look here" > ' . pty])
777  endif
778  call WaitForAssert({-> assert_match('look here', term_getline(buf, 1))})
779
780  bwipe!
781endfunc
782
783func Test_terminal_special_chars()
784  " this file name only works on Unix
785  CheckUnix
786
787  call mkdir('Xdir with spaces')
788  call writefile(['x'], 'Xdir with spaces/quoted"file')
789  term ls Xdir\ with\ spaces/quoted\"file
790  call WaitForAssert({-> assert_match('quoted"file', term_getline('', 1))})
791  " make sure the job has finished
792  call WaitForAssert({-> assert_match('finish', term_getstatus(bufnr()))})
793
794  call delete('Xdir with spaces', 'rf')
795  bwipe
796endfunc
797
798func Test_terminal_wrong_options()
799  call assert_fails('call term_start(&shell, {
800	\ "in_io": "file",
801	\ "in_name": "xxx",
802	\ "out_io": "file",
803	\ "out_name": "xxx",
804	\ "err_io": "file",
805	\ "err_name": "xxx"
806	\ })', 'E474:')
807  call assert_fails('call term_start(&shell, {
808	\ "out_buf": bufnr("%")
809	\ })', 'E474:')
810  call assert_fails('call term_start(&shell, {
811	\ "err_buf": bufnr("%")
812	\ })', 'E474:')
813endfunc
814
815func Test_terminal_redir_file()
816  let cmd = Get_cat_123_cmd()
817  let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'})
818  call TermWait(buf)
819  " ConPTY may precede escape sequence. There are things that are not so.
820  if !has('conpty')
821    call WaitForAssert({-> assert_notequal(0, len(readfile("Xfile")))})
822    call assert_match('123', readfile('Xfile')[0])
823  endif
824  let g:job = term_getjob(buf)
825  call WaitForAssert({-> assert_equal("dead", job_status(g:job))})
826
827  if has('win32')
828    " On Windows we cannot delete a file being used by a process.  When
829    " job_status() returns "dead", the process remains for a short time.
830    " Just wait for a moment.
831    sleep 50m
832  endif
833  call delete('Xfile')
834  bwipe
835
836  if has('unix')
837    call writefile(['one line'], 'Xfile')
838    let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
839    call TermWait(buf)
840    call WaitForAssert({-> assert_equal('one line', term_getline(buf, 1))})
841    let g:job = term_getjob(buf)
842    call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
843    bwipe
844    call delete('Xfile')
845  endif
846endfunc
847
848func TerminalTmap(remap)
849  let buf = Run_shell_in_terminal({})
850  call assert_equal('t', mode())
851
852  if a:remap
853    tmap 123 456
854  else
855    tnoremap 123 456
856  endif
857  " don't use abcde, it's an existing command
858  tmap 456 abxde
859  call assert_equal('456', maparg('123', 't'))
860  call assert_equal('abxde', maparg('456', 't'))
861  call feedkeys("123", 'tx')
862  call WaitForAssert({-> assert_match('abxde\|456', term_getline(buf, term_getcursor(buf)[0]))})
863  let lnum = term_getcursor(buf)[0]
864  if a:remap
865    call assert_match('abxde', term_getline(buf, lnum))
866  else
867    call assert_match('456', term_getline(buf, lnum))
868  endif
869
870  call term_sendkeys(buf, "\r")
871  call StopShellInTerminal(buf)
872  call TermWait(buf)
873
874  tunmap 123
875  tunmap 456
876  call assert_equal('', maparg('123', 't'))
877  close
878  unlet g:job
879endfunc
880
881func Test_terminal_tmap()
882  call TerminalTmap(1)
883  call TerminalTmap(0)
884endfunc
885
886func Test_terminal_wall()
887  let buf = Run_shell_in_terminal({})
888  wall
889  call StopShellInTerminal(buf)
890  call TermWait(buf)
891  exe buf . 'bwipe'
892  unlet g:job
893endfunc
894
895func Test_terminal_wqall()
896  let buf = Run_shell_in_terminal({})
897  call assert_fails('wqall', 'E948')
898  call StopShellInTerminal(buf)
899  call TermWait(buf)
900  exe buf . 'bwipe'
901  unlet g:job
902endfunc
903
904func Test_terminal_composing_unicode()
905  let save_enc = &encoding
906  set encoding=utf-8
907
908  if has('win32')
909    let cmd = "cmd /K chcp 65001"
910    let lnum = [3, 6, 9]
911  else
912    let cmd = &shell
913    let lnum = [1, 3, 5]
914  endif
915
916  enew
917  let buf = term_start(cmd, {'curwin': bufnr('')})
918  let g:job = term_getjob(buf)
919  call WaitFor({-> term_getline(buf, 1) !=# ''}, 1000)
920
921  if has('win32')
922    call assert_equal('cmd', job_info(g:job).cmd[0])
923  else
924    call assert_equal(&shell, job_info(g:job).cmd[0])
925  endif
926
927  " ascii + composing
928  let txt = "a\u0308bc"
929  call term_sendkeys(buf, "echo " . txt)
930  call TermWait(buf, 25)
931  call assert_match("echo " . txt, term_getline(buf, lnum[0]))
932  call term_sendkeys(buf, "\<cr>")
933  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[0] + 1))}, 1000)
934  let l = term_scrape(buf, lnum[0] + 1)
935  call assert_equal("a\u0308", l[0].chars)
936  call assert_equal("b", l[1].chars)
937  call assert_equal("c", l[2].chars)
938
939  " multibyte + composing
940  let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099"
941  call term_sendkeys(buf, "echo " . txt)
942  call TermWait(buf, 25)
943  call assert_match("echo " . txt, term_getline(buf, lnum[1]))
944  call term_sendkeys(buf, "\<cr>")
945  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[1] + 1))}, 1000)
946  let l = term_scrape(buf, lnum[1] + 1)
947  call assert_equal("\u304b\u3099", l[0].chars)
948  call assert_equal("\u304e", l[2].chars)
949  call assert_equal("\u304f\u3099", l[3].chars)
950  call assert_equal("\u3052", l[5].chars)
951  call assert_equal("\u3053\u3099", l[6].chars)
952
953  " \u00a0 + composing
954  let txt = "abc\u00a0\u0308"
955  call term_sendkeys(buf, "echo " . txt)
956  call TermWait(buf, 25)
957  call assert_match("echo " . txt, term_getline(buf, lnum[2]))
958  call term_sendkeys(buf, "\<cr>")
959  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[2] + 1))}, 1000)
960  let l = term_scrape(buf, lnum[2] + 1)
961  call assert_equal("\u00a0\u0308", l[3].chars)
962
963  call term_sendkeys(buf, "exit\r")
964  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
965  bwipe!
966  unlet g:job
967  let &encoding = save_enc
968endfunc
969
970func Test_terminal_aucmd_on_close()
971  fun Nop()
972    let s:called = 1
973  endfun
974
975  aug repro
976      au!
977      au BufWinLeave * call Nop()
978  aug END
979
980  let [cmd, waittime] = s:get_sleep_cmd()
981
982  call assert_equal(1, winnr('$'))
983  new
984  call setline(1, ['one', 'two'])
985  exe 'term ++close ' . cmd
986  wincmd p
987  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
988  call assert_equal(1, s:called)
989  bwipe!
990
991  unlet s:called
992  au! repro
993  delfunc Nop
994endfunc
995
996func Test_terminal_term_start_empty_command()
997  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
998  call assert_fails(cmd, 'E474')
999  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
1000  call assert_fails(cmd, 'E474')
1001  let cmd = "call term_start({}, {'curwin' : 1, 'term_finish' : 'close'})"
1002  call assert_fails(cmd, 'E474')
1003  let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})"
1004  call assert_fails(cmd, 'E474')
1005  let cmd = "call term_start('', {'term_name' : []})"
1006  call assert_fails(cmd, 'E730')
1007  let cmd = "call term_start('', {'term_finish' : 'axby'})"
1008  call assert_fails(cmd, 'E475')
1009  let cmd = "call term_start('', {'eof_chars' : []})"
1010  call assert_fails(cmd, 'E730:')
1011  let cmd = "call term_start('', {'term_kill' : []})"
1012  call assert_fails(cmd, 'E730:')
1013  let cmd = "call term_start('', {'tty_type' : []})"
1014  call assert_fails(cmd, 'E730:')
1015  let cmd = "call term_start('', {'tty_type' : 'abc'})"
1016  call assert_fails(cmd, 'E475:')
1017  let cmd = "call term_start('', {'term_highlight' : []})"
1018  call assert_fails(cmd, 'E730:')
1019  if has('gui') || has('termguicolors')
1020    let cmd = "call term_start('', {'ansi_colors' : 'abc'})"
1021    call assert_fails(cmd, 'E475:')
1022    let cmd = "call term_start('', {'ansi_colors' : [[]]})"
1023    call assert_fails(cmd, 'E730:')
1024    let cmd = "call term_start('', {'ansi_colors' : repeat(['blue'], 18)})"
1025    if has('gui_running') || has('termguicolors')
1026      call assert_fails(cmd, 'E475:')
1027    else
1028      call assert_fails(cmd, 'E254:')
1029    endif
1030  endif
1031endfunc
1032
1033func Test_terminal_response_to_control_sequence()
1034  CheckUnix
1035
1036  let buf = Run_shell_in_terminal({})
1037  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
1038
1039  call term_sendkeys(buf, "cat\<CR>")
1040  call WaitForAssert({-> assert_match('cat', term_getline(buf, 1))})
1041
1042  " Request the cursor position.
1043  call term_sendkeys(buf, "\x1b[6n\<CR>")
1044
1045  " Wait for output from tty to display, below an empty line.
1046  call WaitForAssert({-> assert_match('3;1R', term_getline(buf, 4))})
1047
1048  " End "cat" gently.
1049  call term_sendkeys(buf, "\<CR>\<C-D>")
1050
1051  call StopShellInTerminal(buf)
1052  exe buf . 'bwipe'
1053  unlet g:job
1054endfunc
1055
1056" Run Vim, start a terminal in that Vim with the kill argument,
1057" :qall works.
1058func Run_terminal_qall_kill(line1, line2)
1059  " 1. Open a terminal window and wait for the prompt to appear
1060  " 2. set kill using term_setkill()
1061  " 3. make Vim exit, it will kill the shell
1062  let after = [
1063	\ a:line1,
1064	\ 'let buf = bufnr("%")',
1065	\ 'while term_getline(buf, 1) =~ "^\\s*$"',
1066	\ '  sleep 10m',
1067	\ 'endwhile',
1068	\ a:line2,
1069	\ 'au VimLeavePre * call writefile(["done"], "Xdone")',
1070	\ 'qall',
1071	\ ]
1072  if !RunVim([], after, '')
1073    return
1074  endif
1075  call assert_equal("done", readfile("Xdone")[0])
1076  call delete("Xdone")
1077endfunc
1078
1079" Run Vim in a terminal, then start a terminal in that Vim with a kill
1080" argument, check that :qall works.
1081func Test_terminal_qall_kill_arg()
1082  call Run_terminal_qall_kill('term ++kill=kill', '')
1083endfunc
1084
1085" Run Vim, start a terminal in that Vim, set the kill argument with
1086" term_setkill(), check that :qall works.
1087func Test_terminal_qall_kill_func()
1088  call Run_terminal_qall_kill('term', 'eval buf->term_setkill("kill")')
1089endfunc
1090
1091" Run Vim, start a terminal in that Vim without the kill argument,
1092" check that :qall does not exit, :qall! does.
1093func Test_terminal_qall_exit()
1094  let after =<< trim [CODE]
1095    term
1096    let buf = bufnr("%")
1097    while term_getline(buf, 1) =~ "^\\s*$"
1098      sleep 10m
1099    endwhile
1100    set nomore
1101    au VimLeavePre * call writefile(["too early"], "Xdone")
1102    qall
1103    au! VimLeavePre * exe buf . "bwipe!" | call writefile(["done"], "Xdone")
1104    cquit
1105  [CODE]
1106
1107  if !RunVim([], after, '')
1108    return
1109  endif
1110  call assert_equal("done", readfile("Xdone")[0])
1111  call delete("Xdone")
1112endfunc
1113
1114" Run Vim in a terminal, then start a terminal in that Vim without a kill
1115" argument, check that :confirm qall works.
1116func Test_terminal_qall_prompt()
1117  CheckRunVimInTerminal
1118  let buf = RunVimInTerminal('', {})
1119
1120  " Open a terminal window and wait for the prompt to appear
1121  call term_sendkeys(buf, ":term\<CR>")
1122  call WaitForAssert({-> assert_match('\[running]', term_getline(buf, 10))})
1123  call WaitForAssert({-> assert_notmatch('^\s*$', term_getline(buf, 1))})
1124
1125  " make Vim exit, it will prompt to kill the shell
1126  call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>")
1127  call WaitForAssert({-> assert_match('ancel:', term_getline(buf, 20))})
1128  call term_sendkeys(buf, "y")
1129  call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
1130
1131  " close the terminal window where Vim was running
1132  quit
1133endfunc
1134
1135" Run Vim in a terminal, then start a terminal window with a shell and check
1136" that Vim exits if it is closed.
1137func Test_terminal_exit()
1138  CheckRunVimInTerminal
1139
1140  let lines =<< trim END
1141     let winid = win_getid()
1142     help
1143     term
1144     let termid = win_getid()
1145     call win_gotoid(winid)
1146     close
1147     call win_gotoid(termid)
1148  END
1149  call writefile(lines, 'XtermExit')
1150  let buf = RunVimInTerminal('-S XtermExit', #{rows: 10})
1151  let job = term_getjob(buf)
1152  call WaitForAssert({-> assert_equal("run", job_status(job))})
1153
1154  " quit the shell, it will make Vim exit
1155  call term_sendkeys(buf, "exit\<CR>")
1156  call WaitForAssert({-> assert_equal("dead", job_status(job))})
1157
1158  call delete('XtermExit')
1159endfunc
1160
1161func Test_terminal_open_autocmd()
1162  augroup repro
1163    au!
1164    au TerminalOpen * let s:called += 1
1165  augroup END
1166
1167  let s:called = 0
1168
1169  " Open a terminal window with :terminal
1170  terminal
1171  call assert_equal(1, s:called)
1172  bwipe!
1173
1174  " Open a terminal window with term_start()
1175  call term_start(&shell)
1176  call assert_equal(2, s:called)
1177  bwipe!
1178
1179  " Open a hidden terminal buffer with :terminal
1180  terminal ++hidden
1181  call assert_equal(3, s:called)
1182  for buf in term_list()
1183    exe buf . "bwipe!"
1184  endfor
1185
1186  " Open a hidden terminal buffer with term_start()
1187  let buf = term_start(&shell, {'hidden': 1})
1188  call assert_equal(4, s:called)
1189  exe buf . "bwipe!"
1190
1191  unlet s:called
1192  au! repro
1193endfunction
1194
1195func Check_dump01(off)
1196  call assert_equal('one two three four five', trim(getline(a:off + 1)))
1197  call assert_equal('~           Select Word', trim(getline(a:off + 7)))
1198  call assert_equal(':popup PopUp', trim(getline(a:off + 20)))
1199endfunc
1200
1201func Test_terminal_dumpwrite_composing()
1202  CheckRunVimInTerminal
1203  let save_enc = &encoding
1204  set encoding=utf-8
1205  call assert_equal(1, winnr('$'))
1206
1207  let text = " a\u0300 e\u0302 o\u0308"
1208  call writefile([text], 'Xcomposing')
1209  let buf = RunVimInTerminal('--cmd "set encoding=utf-8" Xcomposing', {})
1210  call WaitForAssert({-> assert_match(text, term_getline(buf, 1))})
1211  eval 'Xdump'->term_dumpwrite(buf)
1212  let dumpline = readfile('Xdump')[0]
1213  call assert_match('|à| |ê| |ö', dumpline)
1214
1215  call StopVimInTerminal(buf)
1216  call delete('Xcomposing')
1217  call delete('Xdump')
1218  let &encoding = save_enc
1219endfunc
1220
1221" Tests for failures in the term_dumpwrite() function
1222func Test_terminal_dumpwrite_errors()
1223  CheckRunVimInTerminal
1224  call assert_fails("call term_dumpwrite({}, 'Xtest.dump')", 'E728:')
1225  let buf = RunVimInTerminal('', {})
1226  call term_wait(buf)
1227  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump', '')", 'E715:')
1228  call assert_fails("call term_dumpwrite(buf, [])", 'E730:')
1229  call writefile([], 'Xtest.dump')
1230  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E953:')
1231  call delete('Xtest.dump')
1232  call assert_fails("call term_dumpwrite(buf, '')", 'E482:')
1233  call assert_fails("call term_dumpwrite(buf, test_null_string())", 'E482:')
1234  call test_garbagecollect_now()
1235  call StopVimInTerminal(buf)
1236  call term_wait(buf)
1237  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E958:')
1238  call assert_fails('call term_sendkeys([], ":q\<CR>")', 'E745:')
1239  call assert_equal(0, term_sendkeys(buf, ":q\<CR>"))
1240endfunc
1241
1242" just testing basic functionality.
1243func Test_terminal_dumpload()
1244  let curbuf = winbufnr('')
1245  call assert_equal(1, winnr('$'))
1246  let buf = term_dumpload('dumps/Test_popup_command_01.dump')
1247  call assert_equal(2, winnr('$'))
1248  call assert_equal(20, line('$'))
1249  call Check_dump01(0)
1250
1251  " Load another dump in the same window
1252  let buf2 = 'dumps/Test_diff_01.dump'->term_dumpload({'bufnr': buf})
1253  call assert_equal(buf, buf2)
1254  call assert_notequal('one two three four five', trim(getline(1)))
1255
1256  " Load the first dump again in the same window
1257  let buf2 = term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': buf})
1258  call assert_equal(buf, buf2)
1259  call Check_dump01(0)
1260
1261  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': curbuf})", 'E475:')
1262  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': 9999})", 'E86:')
1263  new
1264  let closedbuf = winbufnr('')
1265  quit
1266  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': closedbuf})", 'E475:')
1267  call assert_fails('call term_dumpload([])', 'E730:')
1268  call assert_fails('call term_dumpload("xabcy.dump")', 'E485:')
1269
1270  quit
1271endfunc
1272
1273func Test_terminal_dumpload_dump()
1274  CheckRunVimInTerminal
1275
1276  let lines =<< trim END
1277     call term_dumpload('dumps/Test_popupwin_22.dump', #{term_rows: 12})
1278  END
1279  call writefile(lines, 'XtermDumpload')
1280  let buf = RunVimInTerminal('-S XtermDumpload', #{rows: 15})
1281  call VerifyScreenDump(buf, 'Test_terminal_dumpload', {})
1282
1283  call StopVimInTerminal(buf)
1284  call delete('XtermDumpload')
1285endfunc
1286
1287func Test_terminal_dumpdiff()
1288  call assert_equal(1, winnr('$'))
1289  eval 'dumps/Test_popup_command_01.dump'->term_dumpdiff('dumps/Test_popup_command_02.dump')
1290  call assert_equal(2, winnr('$'))
1291  call assert_equal(62, line('$'))
1292  call Check_dump01(0)
1293  call Check_dump01(42)
1294  call assert_equal('           bbbbbbbbbbbbbbbbbb ', getline(26)[0:29])
1295  quit
1296
1297  call assert_fails('call term_dumpdiff("X1.dump", [])', 'E730:')
1298  call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:')
1299  call writefile([], 'X1.dump')
1300  call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:')
1301  call delete('X1.dump')
1302endfunc
1303
1304func Test_terminal_dumpdiff_swap()
1305  call assert_equal(1, winnr('$'))
1306  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_03.dump')
1307  call assert_equal(2, winnr('$'))
1308  call assert_equal(62, line('$'))
1309  call assert_match('Test_popup_command_01.dump', getline(21))
1310  call assert_match('Test_popup_command_03.dump', getline(42))
1311  call assert_match('Undo', getline(3))
1312  call assert_match('three four five', getline(45))
1313
1314  normal s
1315  call assert_match('Test_popup_command_03.dump', getline(21))
1316  call assert_match('Test_popup_command_01.dump', getline(42))
1317  call assert_match('three four five', getline(3))
1318  call assert_match('Undo', getline(45))
1319  quit
1320
1321  " Diff two terminal dump files with different number of rows
1322  " Swap the diffs
1323  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_winline_rnu.dump')
1324  call assert_match('Test_popup_command_01.dump', getline(21))
1325  call assert_match('Test_winline_rnu.dump', getline(42))
1326  normal s
1327  call assert_match('Test_winline_rnu.dump', getline(6))
1328  call assert_match('Test_popup_command_01.dump', getline(27))
1329  quit
1330endfunc
1331
1332func Test_terminal_dumpdiff_options()
1333  set laststatus=0
1334  call assert_equal(1, winnr('$'))
1335  let height = winheight(0)
1336  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 1, 'term_cols': 33})
1337  call assert_equal(2, winnr('$'))
1338  call assert_equal(height, winheight(winnr()))
1339  call assert_equal(33, winwidth(winnr()))
1340  call assert_equal('dump diff dumps/Test_popup_command_01.dump', bufname('%'))
1341  quit
1342
1343  call assert_equal(1, winnr('$'))
1344  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 0, 'term_rows': 13, 'term_name': 'something else'})
1345  call assert_equal(2, winnr('$'))
1346  call assert_equal(&columns, winwidth(0))
1347  call assert_equal(13, winheight(0))
1348  call assert_equal('something else', bufname('%'))
1349  quit
1350
1351  call assert_equal(1, winnr('$'))
1352  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1})
1353  call assert_equal(1, winnr('$'))
1354  call assert_fails("call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'bufnr': -1})", 'E475:')
1355  bwipe
1356
1357  set laststatus&
1358endfunc
1359
1360" When drawing the statusline the cursor position may not have been updated
1361" yet.
1362" 1. create a terminal, make it show 2 lines
1363" 2. 0.5 sec later: leave terminal window, execute "i"
1364" 3. 0.5 sec later: clear terminal window, now it's 1 line
1365" 4. 0.5 sec later: redraw, including statusline (used to trigger bug)
1366" 4. 0.5 sec later: should be done, clean up
1367func Test_terminal_statusline()
1368  CheckUnix
1369
1370  set statusline=x
1371  terminal
1372  let tbuf = bufnr('')
1373  call term_sendkeys(tbuf, "clear; echo a; echo b; sleep 1; clear\n")
1374  call timer_start(500, { tid -> feedkeys("\<C-w>j", 'tx') })
1375  call timer_start(1500, { tid -> feedkeys("\<C-l>", 'tx') })
1376  au BufLeave * if &buftype == 'terminal' | silent! normal i | endif
1377
1378  sleep 2
1379  exe tbuf . 'bwipe!'
1380  au! BufLeave
1381  set statusline=
1382endfunc
1383
1384func Api_drop_common(options)
1385  call assert_equal(1, winnr('$'))
1386
1387  " Use the title termcap entries to output the escape sequence.
1388  call writefile([
1389	\ 'set title',
1390	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1391	\ 'let &titlestring = ''["drop","Xtextfile"' . a:options . ']''',
1392	\ 'redraw',
1393	\ "set t_ts=",
1394	\ ], 'Xscript')
1395  let buf = RunVimInTerminal('-S Xscript', {})
1396  call WaitFor({-> bufnr('Xtextfile') > 0})
1397  call assert_equal('Xtextfile', expand('%:t'))
1398  call assert_true(winnr('$') >= 3)
1399  return buf
1400endfunc
1401
1402func Test_terminal_api_drop_newwin()
1403  CheckRunVimInTerminal
1404  let buf = Api_drop_common('')
1405  call assert_equal(0, &bin)
1406  call assert_equal('', &fenc)
1407
1408  call StopVimInTerminal(buf)
1409  call delete('Xscript')
1410  bwipe Xtextfile
1411endfunc
1412
1413func Test_terminal_api_drop_newwin_bin()
1414  CheckRunVimInTerminal
1415  let buf = Api_drop_common(',{"bin":1}')
1416  call assert_equal(1, &bin)
1417
1418  call StopVimInTerminal(buf)
1419  call delete('Xscript')
1420  bwipe Xtextfile
1421endfunc
1422
1423func Test_terminal_api_drop_newwin_binary()
1424  CheckRunVimInTerminal
1425  let buf = Api_drop_common(',{"binary":1}')
1426  call assert_equal(1, &bin)
1427
1428  call StopVimInTerminal(buf)
1429  call delete('Xscript')
1430  bwipe Xtextfile
1431endfunc
1432
1433func Test_terminal_api_drop_newwin_nobin()
1434  CheckRunVimInTerminal
1435  set binary
1436  let buf = Api_drop_common(',{"nobin":1}')
1437  call assert_equal(0, &bin)
1438
1439  call StopVimInTerminal(buf)
1440  call delete('Xscript')
1441  bwipe Xtextfile
1442  set nobinary
1443endfunc
1444
1445func Test_terminal_api_drop_newwin_nobinary()
1446  CheckRunVimInTerminal
1447  set binary
1448  let buf = Api_drop_common(',{"nobinary":1}')
1449  call assert_equal(0, &bin)
1450
1451  call StopVimInTerminal(buf)
1452  call delete('Xscript')
1453  bwipe Xtextfile
1454  set nobinary
1455endfunc
1456
1457func Test_terminal_api_drop_newwin_ff()
1458  CheckRunVimInTerminal
1459  let buf = Api_drop_common(',{"ff":"dos"}')
1460  call assert_equal("dos", &ff)
1461
1462  call StopVimInTerminal(buf)
1463  call delete('Xscript')
1464  bwipe Xtextfile
1465endfunc
1466
1467func Test_terminal_api_drop_newwin_fileformat()
1468  CheckRunVimInTerminal
1469  let buf = Api_drop_common(',{"fileformat":"dos"}')
1470  call assert_equal("dos", &ff)
1471
1472  call StopVimInTerminal(buf)
1473  call delete('Xscript')
1474  bwipe Xtextfile
1475endfunc
1476
1477func Test_terminal_api_drop_newwin_enc()
1478  CheckRunVimInTerminal
1479  let buf = Api_drop_common(',{"enc":"utf-16"}')
1480  call assert_equal("utf-16", &fenc)
1481
1482  call StopVimInTerminal(buf)
1483  call delete('Xscript')
1484  bwipe Xtextfile
1485endfunc
1486
1487func Test_terminal_api_drop_newwin_encoding()
1488  CheckRunVimInTerminal
1489  let buf = Api_drop_common(',{"encoding":"utf-16"}')
1490  call assert_equal("utf-16", &fenc)
1491
1492  call StopVimInTerminal(buf)
1493  call delete('Xscript')
1494  bwipe Xtextfile
1495endfunc
1496
1497func Test_terminal_api_drop_oldwin()
1498  CheckRunVimInTerminal
1499  let firstwinid = win_getid()
1500  split Xtextfile
1501  let textfile_winid = win_getid()
1502  call assert_equal(2, winnr('$'))
1503  call win_gotoid(firstwinid)
1504
1505  " Use the title termcap entries to output the escape sequence.
1506  call writefile([
1507	\ 'set title',
1508	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1509	\ 'let &titlestring = ''["drop","Xtextfile"]''',
1510	\ 'redraw',
1511	\ "set t_ts=",
1512	\ ], 'Xscript')
1513  let buf = RunVimInTerminal('-S Xscript', {'rows': 10})
1514  call WaitForAssert({-> assert_equal('Xtextfile', expand('%:t'))})
1515  call assert_equal(textfile_winid, win_getid())
1516
1517  call StopVimInTerminal(buf)
1518  call delete('Xscript')
1519  bwipe Xtextfile
1520endfunc
1521
1522func Tapi_TryThis(bufnum, arg)
1523  let g:called_bufnum = a:bufnum
1524  let g:called_arg = a:arg
1525endfunc
1526
1527func WriteApiCall(funcname)
1528  " Use the title termcap entries to output the escape sequence.
1529  call writefile([
1530	\ 'set title',
1531	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1532	\ 'let &titlestring = ''["call","' . a:funcname . '",["hello",123]]''',
1533	\ 'redraw',
1534	\ "set t_ts=",
1535	\ ], 'Xscript')
1536endfunc
1537
1538func Test_terminal_api_call()
1539  CheckRunVimInTerminal
1540
1541  unlet! g:called_bufnum
1542  unlet! g:called_arg
1543
1544  call WriteApiCall('Tapi_TryThis')
1545
1546  " Default
1547  let buf = RunVimInTerminal('-S Xscript', {})
1548  call WaitFor({-> exists('g:called_bufnum')})
1549  call assert_equal(buf, g:called_bufnum)
1550  call assert_equal(['hello', 123], g:called_arg)
1551  call StopVimInTerminal(buf)
1552
1553  unlet! g:called_bufnum
1554  unlet! g:called_arg
1555
1556  " Enable explicitly
1557  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'Tapi_Try'})
1558  call WaitFor({-> exists('g:called_bufnum')})
1559  call assert_equal(buf, g:called_bufnum)
1560  call assert_equal(['hello', 123], g:called_arg)
1561  call StopVimInTerminal(buf)
1562
1563  unlet! g:called_bufnum
1564  unlet! g:called_arg
1565
1566  func! ApiCall_TryThis(bufnum, arg)
1567    let g:called_bufnum2 = a:bufnum
1568    let g:called_arg2 = a:arg
1569  endfunc
1570
1571  call WriteApiCall('ApiCall_TryThis')
1572
1573  " Use prefix match
1574  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'ApiCall_'})
1575  call WaitFor({-> exists('g:called_bufnum2')})
1576  call assert_equal(buf, g:called_bufnum2)
1577  call assert_equal(['hello', 123], g:called_arg2)
1578  call StopVimInTerminal(buf)
1579
1580  call assert_fails("call term_start('ls', {'term_api' : []})", 'E730:')
1581
1582  unlet! g:called_bufnum2
1583  unlet! g:called_arg2
1584
1585  call delete('Xscript')
1586  delfunction! ApiCall_TryThis
1587  unlet! g:called_bufnum2
1588  unlet! g:called_arg2
1589endfunc
1590
1591func Test_terminal_api_call_fails()
1592  CheckRunVimInTerminal
1593
1594  func! TryThis(bufnum, arg)
1595    let g:called_bufnum3 = a:bufnum
1596    let g:called_arg3 = a:arg
1597  endfunc
1598
1599  call WriteApiCall('TryThis')
1600
1601  unlet! g:called_bufnum3
1602  unlet! g:called_arg3
1603
1604  " Not permitted
1605  call ch_logfile('Xlog', 'w')
1606  let buf = RunVimInTerminal('-S Xscript', {'term_api': ''})
1607  call WaitForAssert({-> assert_match('Unpermitted function: TryThis', string(readfile('Xlog')))})
1608  call assert_false(exists('g:called_bufnum3'))
1609  call assert_false(exists('g:called_arg3'))
1610  call StopVimInTerminal(buf)
1611
1612  " No match
1613  call ch_logfile('Xlog', 'w')
1614  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'TryThat'})
1615  call WaitFor({-> string(readfile('Xlog')) =~ 'Unpermitted function: TryThis'})
1616  call assert_false(exists('g:called_bufnum3'))
1617  call assert_false(exists('g:called_arg3'))
1618  call StopVimInTerminal(buf)
1619
1620  call delete('Xscript')
1621  call ch_logfile('')
1622  call delete('Xlog')
1623  delfunction! TryThis
1624  unlet! g:called_bufnum3
1625  unlet! g:called_arg3
1626endfunc
1627
1628let s:caught_e937 = 0
1629
1630func Tapi_Delete(bufnum, arg)
1631  try
1632    execute 'bdelete!' a:bufnum
1633  catch /E937:/
1634    let s:caught_e937 = 1
1635  endtry
1636endfunc
1637
1638func Test_terminal_api_call_fail_delete()
1639  CheckRunVimInTerminal
1640
1641  call WriteApiCall('Tapi_Delete')
1642  let buf = RunVimInTerminal('-S Xscript', {})
1643  call WaitForAssert({-> assert_equal(1, s:caught_e937)})
1644
1645  call StopVimInTerminal(buf)
1646  call delete('Xscript')
1647  call ch_logfile('', '')
1648endfunc
1649
1650func Test_terminal_setapi_and_call()
1651  CheckRunVimInTerminal
1652
1653  call WriteApiCall('Tapi_TryThis')
1654  call ch_logfile('Xlog', 'w')
1655
1656  unlet! g:called_bufnum
1657  unlet! g:called_arg
1658
1659  let buf = RunVimInTerminal('-S Xscript', {'term_api': ''})
1660  call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))})
1661  call assert_false(exists('g:called_bufnum'))
1662  call assert_false(exists('g:called_arg'))
1663
1664  eval buf->term_setapi('Tapi_')
1665  call term_sendkeys(buf, ":set notitle\<CR>")
1666  call term_sendkeys(buf, ":source Xscript\<CR>")
1667  call WaitFor({-> exists('g:called_bufnum')})
1668  call assert_equal(buf, g:called_bufnum)
1669  call assert_equal(['hello', 123], g:called_arg)
1670
1671  call StopVimInTerminal(buf)
1672
1673  call delete('Xscript')
1674  call ch_logfile('')
1675  call delete('Xlog')
1676  unlet! g:called_bufnum
1677  unlet! g:called_arg
1678endfunc
1679
1680func Test_terminal_api_arg()
1681  CheckRunVimInTerminal
1682
1683  call WriteApiCall('Tapi_TryThis')
1684  call ch_logfile('Xlog', 'w')
1685
1686  unlet! g:called_bufnum
1687  unlet! g:called_arg
1688
1689  execute 'term ++api= ' .. GetVimCommandCleanTerm() .. '-S Xscript'
1690  let buf = bufnr('%')
1691  call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))})
1692  call assert_false(exists('g:called_bufnum'))
1693  call assert_false(exists('g:called_arg'))
1694
1695  call StopVimInTerminal(buf)
1696
1697  call ch_logfile('Xlog', 'w')
1698
1699  execute 'term ++api=Tapi_ ' .. GetVimCommandCleanTerm() .. '-S Xscript'
1700  let buf = bufnr('%')
1701  call WaitFor({-> exists('g:called_bufnum')})
1702  call assert_equal(buf, g:called_bufnum)
1703  call assert_equal(['hello', 123], g:called_arg)
1704
1705  call StopVimInTerminal(buf)
1706
1707  call delete('Xscript')
1708  call ch_logfile('')
1709  call delete('Xlog')
1710  unlet! g:called_bufnum
1711  unlet! g:called_arg
1712endfunc
1713
1714func Test_terminal_ansicolors_default()
1715  CheckFunction term_getansicolors
1716
1717  let colors = [
1718	\ '#000000', '#e00000',
1719	\ '#00e000', '#e0e000',
1720	\ '#0000e0', '#e000e0',
1721	\ '#00e0e0', '#e0e0e0',
1722	\ '#808080', '#ff4040',
1723	\ '#40ff40', '#ffff40',
1724	\ '#4040ff', '#ff40ff',
1725	\ '#40ffff', '#ffffff',
1726	\]
1727
1728  let buf = Run_shell_in_terminal({})
1729  call assert_equal(colors, term_getansicolors(buf))
1730  call StopShellInTerminal(buf)
1731  call TermWait(buf)
1732  call assert_equal([], term_getansicolors(buf))
1733
1734  exe buf . 'bwipe'
1735endfunc
1736
1737let s:test_colors = [
1738	\ '#616e64', '#0d0a79',
1739	\ '#6d610d', '#0a7373',
1740	\ '#690d0a', '#6d696e',
1741	\ '#0d0a6f', '#616e0d',
1742	\ '#0a6479', '#6d0d0a',
1743	\ '#617373', '#0d0a69',
1744	\ '#6d690d', '#0a6e6f',
1745	\ '#610d0a', '#6e6479',
1746	\]
1747
1748func Test_terminal_ansicolors_global()
1749  CheckFeature termguicolors
1750  CheckFunction term_getansicolors
1751
1752  let g:terminal_ansi_colors = reverse(copy(s:test_colors))
1753  let buf = Run_shell_in_terminal({})
1754  call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
1755  call StopShellInTerminal(buf)
1756  call TermWait(buf)
1757
1758  exe buf . 'bwipe'
1759  unlet g:terminal_ansi_colors
1760endfunc
1761
1762func Test_terminal_ansicolors_func()
1763  CheckFeature termguicolors
1764  CheckFunction term_getansicolors
1765
1766  let g:terminal_ansi_colors = reverse(copy(s:test_colors))
1767  let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors})
1768  call assert_equal(s:test_colors, term_getansicolors(buf))
1769
1770  call term_setansicolors(buf, g:terminal_ansi_colors)
1771  call assert_equal(g:terminal_ansi_colors, buf->term_getansicolors())
1772
1773  let colors = [
1774	\ 'ivory', 'AliceBlue',
1775	\ 'grey67', 'dark goldenrod',
1776	\ 'SteelBlue3', 'PaleVioletRed4',
1777	\ 'MediumPurple2', 'yellow2',
1778	\ 'RosyBrown3', 'OrangeRed2',
1779	\ 'white smoke', 'navy blue',
1780	\ 'grey47', 'gray97',
1781	\ 'MistyRose2', 'DodgerBlue4',
1782	\]
1783  eval buf->term_setansicolors(colors)
1784
1785  let colors[4] = 'Invalid'
1786  call assert_fails('call term_setansicolors(buf, colors)', 'E254:')
1787  call assert_fails('call term_setansicolors(buf, {})', 'E714:')
1788
1789  call StopShellInTerminal(buf)
1790  call TermWait(buf)
1791  call assert_equal(0, term_setansicolors(buf, []))
1792  exe buf . 'bwipe'
1793endfunc
1794
1795func Test_terminal_all_ansi_colors()
1796  CheckRunVimInTerminal
1797
1798  " Use all the ANSI colors.
1799  call writefile([
1800	\ 'call setline(1, "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPP XXYYZZ")',
1801	\ 'hi Tblack ctermfg=0 ctermbg=8',
1802	\ 'hi Tdarkred ctermfg=1 ctermbg=9',
1803	\ 'hi Tdarkgreen ctermfg=2 ctermbg=10',
1804	\ 'hi Tbrown ctermfg=3 ctermbg=11',
1805	\ 'hi Tdarkblue ctermfg=4 ctermbg=12',
1806	\ 'hi Tdarkmagenta ctermfg=5 ctermbg=13',
1807	\ 'hi Tdarkcyan ctermfg=6 ctermbg=14',
1808	\ 'hi Tlightgrey ctermfg=7 ctermbg=15',
1809	\ 'hi Tdarkgrey ctermfg=8 ctermbg=0',
1810	\ 'hi Tred ctermfg=9 ctermbg=1',
1811	\ 'hi Tgreen ctermfg=10 ctermbg=2',
1812	\ 'hi Tyellow ctermfg=11 ctermbg=3',
1813	\ 'hi Tblue ctermfg=12 ctermbg=4',
1814	\ 'hi Tmagenta ctermfg=13 ctermbg=5',
1815	\ 'hi Tcyan ctermfg=14 ctermbg=6',
1816	\ 'hi Twhite ctermfg=15 ctermbg=7',
1817	\ 'hi TdarkredBold ctermfg=1 cterm=bold',
1818	\ 'hi TgreenBold ctermfg=10 cterm=bold',
1819	\ 'hi TmagentaBold ctermfg=13 cterm=bold ctermbg=5',
1820	\ '',
1821	\ 'call  matchadd("Tblack", "A")',
1822	\ 'call  matchadd("Tdarkred", "B")',
1823	\ 'call  matchadd("Tdarkgreen", "C")',
1824	\ 'call  matchadd("Tbrown", "D")',
1825	\ 'call  matchadd("Tdarkblue", "E")',
1826	\ 'call  matchadd("Tdarkmagenta", "F")',
1827	\ 'call  matchadd("Tdarkcyan", "G")',
1828	\ 'call  matchadd("Tlightgrey", "H")',
1829	\ 'call  matchadd("Tdarkgrey", "I")',
1830	\ 'call  matchadd("Tred", "J")',
1831	\ 'call  matchadd("Tgreen", "K")',
1832	\ 'call  matchadd("Tyellow", "L")',
1833	\ 'call  matchadd("Tblue", "M")',
1834	\ 'call  matchadd("Tmagenta", "N")',
1835	\ 'call  matchadd("Tcyan", "O")',
1836	\ 'call  matchadd("Twhite", "P")',
1837	\ 'call  matchadd("TdarkredBold", "X")',
1838	\ 'call  matchadd("TgreenBold", "Y")',
1839	\ 'call  matchadd("TmagentaBold", "Z")',
1840	\ 'redraw',
1841	\ ], 'Xcolorscript')
1842  let buf = RunVimInTerminal('-S Xcolorscript', {'rows': 10})
1843  call VerifyScreenDump(buf, 'Test_terminal_all_ansi_colors', {})
1844
1845  call term_sendkeys(buf, ":q\<CR>")
1846  call StopVimInTerminal(buf)
1847  call delete('Xcolorscript')
1848endfunc
1849
1850
1851" vim: shiftwidth=2 sts=2 expandtab
1852