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 TermWait(buf, 100)
268  exe "set columns=" .. (width / 2)
269  redraw
270  call term_sendkeys(buf, "キ")
271  call TermWait(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  CheckFeature clientserver
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 TermWait(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->TermWait()
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', ['E89:', 'E517:'])
652  exe buf . 'bwipe!'
653  call assert_equal("", bufname(buf))
654endfunction
655
656func Test_terminal_noblock()
657  let buf = term_start(&shell)
658  let wait_time = 5000
659  let letters = 'abcdefghijklmnopqrstuvwxyz'
660  if has('bsd') || has('mac') || has('sun')
661    " The shell or something else has a problem dealing with more than 1000
662    " characters at the same time.  It's very slow too.
663    let len = 1000
664    let wait_time = 15000
665    let letters = 'abcdefghijklm'
666  " NPFS is used in Windows, nonblocking mode does not work properly.
667  elseif has('win32')
668    let len = 1
669  else
670    let len = 5000
671  endif
672
673  " Send a lot of text lines, should be buffered properly.
674  for c in split(letters, '\zs')
675    call term_sendkeys(buf, 'echo ' . repeat(c, len) . "\<cr>")
676  endfor
677  call term_sendkeys(buf, "echo done\<cr>")
678
679  " On MS-Windows there is an extra empty line below "done".  Find "done" in
680  " the last-but-one or the last-but-two line.
681  let lnum = term_getsize(buf)[0] - 1
682  call WaitForAssert({-> assert_match('done', term_getline(buf, lnum - 1) .. '//' .. term_getline(buf, lnum))}, wait_time)
683  let line = term_getline(buf, lnum)
684  if line !~ 'done'
685    let line = term_getline(buf, lnum - 1)
686  endif
687  call assert_match('done', line)
688
689  let g:job = term_getjob(buf)
690  call StopShellInTerminal(buf)
691  call TermWait(buf)
692  unlet g:job
693  bwipe
694endfunc
695
696func Test_terminal_write_stdin()
697  " TODO: enable once writing to stdin works on MS-Windows
698  CheckNotMSWindows
699  CheckExecutable wc
700
701  call setline(1, ['one', 'two', 'three'])
702  %term wc
703  call WaitForAssert({-> assert_match('3', getline("$"))})
704  let nrs = split(getline('$'))
705  call assert_equal(['3', '3', '14'], nrs)
706  %bwipe!
707
708  call setline(1, ['one', 'two', 'three', 'four'])
709  2,3term wc
710  call WaitForAssert({-> assert_match('2', getline("$"))})
711  let nrs = split(getline('$'))
712  call assert_equal(['2', '2', '10'], nrs)
713  %bwipe!
714endfunc
715
716func Test_terminal_eof_arg()
717  call CheckPython(s:python)
718
719  call setline(1, ['print("hello")'])
720  exe '1term ++eof=exit(123) ' .. s:python
721  " MS-Windows echoes the input, Unix doesn't.
722  if has('win32')
723    call WaitFor({-> getline('$') =~ 'exit(123)'})
724    call assert_equal('hello', getline(line('$') - 1))
725  else
726    call WaitFor({-> getline('$') =~ 'hello'})
727    call assert_equal('hello', getline('$'))
728  endif
729  call assert_equal(123, bufnr()->term_getjob()->job_info().exitval)
730  %bwipe!
731endfunc
732
733func Test_terminal_eof_arg_win32_ctrl_z()
734  CheckMSWindows
735  call CheckPython(s:python)
736
737  call setline(1, ['print("hello")'])
738  exe '1term ++eof=<C-Z> ' .. s:python
739  call WaitForAssert({-> assert_match('\^Z', getline(line('$') - 1))})
740  call assert_match('\^Z', getline(line('$') - 1))
741  %bwipe!
742endfunc
743
744func Test_terminal_duplicate_eof_arg()
745  call CheckPython(s:python)
746
747  " Check the last specified ++eof arg is used and should not memory leak.
748  new
749  call setline(1, ['print("hello")'])
750  exe '1term ++eof=<C-Z> ++eof=exit(123) ' .. s:python
751  " MS-Windows echoes the input, Unix doesn't.
752  if has('win32')
753    call WaitFor({-> getline('$') =~ 'exit(123)'})
754    call assert_equal('hello', getline(line('$') - 1))
755  else
756    call WaitFor({-> getline('$') =~ 'hello'})
757    call assert_equal('hello', getline('$'))
758  endif
759  call assert_equal(123, bufnr()->term_getjob()->job_info().exitval)
760  %bwipe!
761endfunc
762
763func Test_terminal_no_cmd()
764  let buf = term_start('NONE', {})
765  call assert_notequal(0, buf)
766
767  let pty = job_info(term_getjob(buf))['tty_out']
768  call assert_notequal('', pty)
769  if has('gui_running') && !has('win32')
770    " In the GUI job_start() doesn't work, it does not read from the pty.
771    call system('echo "look here" > ' . pty)
772  else
773    " Otherwise using a job works on all systems.
774    call job_start([&shell, &shellcmdflag, 'echo "look here" > ' . pty])
775  endif
776  call WaitForAssert({-> assert_match('look here', term_getline(buf, 1))})
777
778  bwipe!
779endfunc
780
781func Test_terminal_special_chars()
782  " this file name only works on Unix
783  CheckUnix
784
785  call mkdir('Xdir with spaces')
786  call writefile(['x'], 'Xdir with spaces/quoted"file')
787  term ls Xdir\ with\ spaces/quoted\"file
788  call WaitForAssert({-> assert_match('quoted"file', term_getline('', 1))})
789  " make sure the job has finished
790  call WaitForAssert({-> assert_match('finish', term_getstatus(bufnr()))})
791
792  call delete('Xdir with spaces', 'rf')
793  bwipe
794endfunc
795
796func Test_terminal_wrong_options()
797  call assert_fails('call term_start(&shell, {
798	\ "in_io": "file",
799	\ "in_name": "xxx",
800	\ "out_io": "file",
801	\ "out_name": "xxx",
802	\ "err_io": "file",
803	\ "err_name": "xxx"
804	\ })', 'E474:')
805  call assert_fails('call term_start(&shell, {
806	\ "out_buf": bufnr("%")
807	\ })', 'E474:')
808  call assert_fails('call term_start(&shell, {
809	\ "err_buf": bufnr("%")
810	\ })', 'E474:')
811endfunc
812
813func Test_terminal_redir_file()
814  let cmd = Get_cat_123_cmd()
815  let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'})
816  call TermWait(buf)
817  " ConPTY may precede escape sequence. There are things that are not so.
818  if !has('conpty')
819    call WaitForAssert({-> assert_notequal(0, len(readfile("Xfile")))})
820    call assert_match('123', readfile('Xfile')[0])
821  endif
822  let g:job = term_getjob(buf)
823  call WaitForAssert({-> assert_equal("dead", job_status(g:job))})
824
825  if has('win32')
826    " On Windows we cannot delete a file being used by a process.  When
827    " job_status() returns "dead", the process remains for a short time.
828    " Just wait for a moment.
829    sleep 50m
830  endif
831  call delete('Xfile')
832  bwipe
833
834  if has('unix')
835    call writefile(['one line'], 'Xfile')
836    let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
837    call TermWait(buf)
838    call WaitForAssert({-> assert_equal('one line', term_getline(buf, 1))})
839    let g:job = term_getjob(buf)
840    call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
841    bwipe
842    call delete('Xfile')
843  endif
844endfunc
845
846func TerminalTmap(remap)
847  let buf = Run_shell_in_terminal({})
848  call assert_equal('t', mode())
849
850  if a:remap
851    tmap 123 456
852  else
853    tnoremap 123 456
854  endif
855  " don't use abcde, it's an existing command
856  tmap 456 abxde
857  call assert_equal('456', maparg('123', 't'))
858  call assert_equal('abxde', maparg('456', 't'))
859  call feedkeys("123", 'tx')
860  call WaitForAssert({-> assert_match('abxde\|456', term_getline(buf, term_getcursor(buf)[0]))})
861  let lnum = term_getcursor(buf)[0]
862  if a:remap
863    call assert_match('abxde', term_getline(buf, lnum))
864  else
865    call assert_match('456', term_getline(buf, lnum))
866  endif
867
868  call term_sendkeys(buf, "\r")
869  call StopShellInTerminal(buf)
870  call TermWait(buf)
871
872  tunmap 123
873  tunmap 456
874  call assert_equal('', maparg('123', 't'))
875  close
876  unlet g:job
877endfunc
878
879func Test_terminal_tmap()
880  call TerminalTmap(1)
881  call TerminalTmap(0)
882endfunc
883
884func Test_terminal_wall()
885  let buf = Run_shell_in_terminal({})
886  wall
887  call StopShellInTerminal(buf)
888  call TermWait(buf)
889  exe buf . 'bwipe'
890  unlet g:job
891endfunc
892
893func Test_terminal_wqall()
894  let buf = Run_shell_in_terminal({})
895  call assert_fails('wqall', 'E948:')
896  call StopShellInTerminal(buf)
897  call TermWait(buf)
898  exe buf . 'bwipe'
899  unlet g:job
900endfunc
901
902func Test_terminal_composing_unicode()
903  let save_enc = &encoding
904  set encoding=utf-8
905
906  if has('win32')
907    let cmd = "cmd /K chcp 65001"
908    let lnum = [3, 6, 9]
909  else
910    let cmd = &shell
911    let lnum = [1, 3, 5]
912  endif
913
914  enew
915  let buf = term_start(cmd, {'curwin': bufnr('')})
916  let g:job = term_getjob(buf)
917  call WaitFor({-> term_getline(buf, 1) !=# ''}, 1000)
918
919  if has('win32')
920    call assert_equal('cmd', job_info(g:job).cmd[0])
921  else
922    call assert_equal(&shell, job_info(g:job).cmd[0])
923  endif
924
925  " ascii + composing
926  let txt = "a\u0308bc"
927  call term_sendkeys(buf, "echo " . txt)
928  call TermWait(buf, 25)
929  call assert_match("echo " . txt, term_getline(buf, lnum[0]))
930  call term_sendkeys(buf, "\<cr>")
931  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[0] + 1))}, 1000)
932  let l = term_scrape(buf, lnum[0] + 1)
933  call assert_equal("a\u0308", l[0].chars)
934  call assert_equal("b", l[1].chars)
935  call assert_equal("c", l[2].chars)
936
937  " multibyte + composing
938  let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099"
939  call term_sendkeys(buf, "echo " . txt)
940  call TermWait(buf, 25)
941  call assert_match("echo " . txt, term_getline(buf, lnum[1]))
942  call term_sendkeys(buf, "\<cr>")
943  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[1] + 1))}, 1000)
944  let l = term_scrape(buf, lnum[1] + 1)
945  call assert_equal("\u304b\u3099", l[0].chars)
946  call assert_equal("\u304e", l[2].chars)
947  call assert_equal("\u304f\u3099", l[3].chars)
948  call assert_equal("\u3052", l[5].chars)
949  call assert_equal("\u3053\u3099", l[6].chars)
950
951  " \u00a0 + composing
952  let txt = "abc\u00a0\u0308"
953  call term_sendkeys(buf, "echo " . txt)
954  call TermWait(buf, 25)
955  call assert_match("echo " . txt, term_getline(buf, lnum[2]))
956  call term_sendkeys(buf, "\<cr>")
957  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[2] + 1))}, 1000)
958  let l = term_scrape(buf, lnum[2] + 1)
959  call assert_equal("\u00a0\u0308", l[3].chars)
960
961  call term_sendkeys(buf, "exit\r")
962  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
963  bwipe!
964  unlet g:job
965  let &encoding = save_enc
966endfunc
967
968func Test_terminal_aucmd_on_close()
969  fun Nop()
970    let s:called = 1
971  endfun
972
973  aug repro
974      au!
975      au BufWinLeave * call Nop()
976  aug END
977
978  let [cmd, waittime] = s:get_sleep_cmd()
979
980  call assert_equal(1, winnr('$'))
981  new
982  call setline(1, ['one', 'two'])
983  exe 'term ++close ' . cmd
984  wincmd p
985  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
986  call assert_equal(1, s:called)
987  bwipe!
988
989  unlet s:called
990  au! repro
991  delfunc Nop
992endfunc
993
994func Test_terminal_term_start_empty_command()
995  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
996  call assert_fails(cmd, 'E474:')
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(0, {'curwin' : 1, 'term_finish' : 'close'})"
1002  call assert_fails(cmd, 'E474:')
1003  let cmd = "call term_start('', {'term_name' : []})"
1004  call assert_fails(cmd, 'E730:')
1005  let cmd = "call term_start('', {'term_finish' : 'axby'})"
1006  call assert_fails(cmd, 'E475:')
1007  let cmd = "call term_start('', {'eof_chars' : []})"
1008  call assert_fails(cmd, 'E730:')
1009  let cmd = "call term_start('', {'term_kill' : []})"
1010  call assert_fails(cmd, 'E730:')
1011  let cmd = "call term_start('', {'tty_type' : []})"
1012  call assert_fails(cmd, 'E730:')
1013  let cmd = "call term_start('', {'tty_type' : 'abc'})"
1014  call assert_fails(cmd, 'E475:')
1015  let cmd = "call term_start('', {'term_highlight' : []})"
1016  call assert_fails(cmd, 'E730:')
1017  if has('gui') || has('termguicolors')
1018    let cmd = "call term_start('', {'ansi_colors' : 'abc'})"
1019    call assert_fails(cmd, 'E475:')
1020    let cmd = "call term_start('', {'ansi_colors' : [[]]})"
1021    call assert_fails(cmd, 'E730:')
1022    let cmd = "call term_start('', {'ansi_colors' : repeat(['blue'], 18)})"
1023    if has('gui_running') || has('termguicolors')
1024      call assert_fails(cmd, 'E475:')
1025    else
1026      call assert_fails(cmd, 'E254:')
1027    endif
1028  endif
1029endfunc
1030
1031func Test_terminal_response_to_control_sequence()
1032  CheckUnix
1033
1034  let buf = Run_shell_in_terminal({})
1035  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
1036
1037  call term_sendkeys(buf, "cat\<CR>")
1038  call WaitForAssert({-> assert_match('cat', term_getline(buf, 1))})
1039
1040  " Request the cursor position.
1041  call term_sendkeys(buf, "\x1b[6n\<CR>")
1042
1043  " Wait for output from tty to display, below an empty line.
1044  call WaitForAssert({-> assert_match('3;1R', term_getline(buf, 4))})
1045
1046  " End "cat" gently.
1047  call term_sendkeys(buf, "\<CR>\<C-D>")
1048
1049  call StopShellInTerminal(buf)
1050  exe buf . 'bwipe'
1051  unlet g:job
1052endfunc
1053
1054" Run Vim, start a terminal in that Vim with the kill argument,
1055" :qall works.
1056func Run_terminal_qall_kill(line1, line2)
1057  " 1. Open a terminal window and wait for the prompt to appear
1058  " 2. set kill using term_setkill()
1059  " 3. make Vim exit, it will kill the shell
1060  let after = [
1061	\ a:line1,
1062	\ 'let buf = bufnr("%")',
1063	\ 'while term_getline(buf, 1) =~ "^\\s*$"',
1064	\ '  sleep 10m',
1065	\ 'endwhile',
1066	\ a:line2,
1067	\ 'au VimLeavePre * call writefile(["done"], "Xdone")',
1068	\ 'qall',
1069	\ ]
1070  if !RunVim([], after, '')
1071    return
1072  endif
1073  call assert_equal("done", readfile("Xdone")[0])
1074  call delete("Xdone")
1075endfunc
1076
1077" Run Vim in a terminal, then start a terminal in that Vim with a kill
1078" argument, check that :qall works.
1079func Test_terminal_qall_kill_arg()
1080  call Run_terminal_qall_kill('term ++kill=kill', '')
1081endfunc
1082
1083" Run Vim, start a terminal in that Vim, set the kill argument with
1084" term_setkill(), check that :qall works.
1085func Test_terminal_qall_kill_func()
1086  call Run_terminal_qall_kill('term', 'eval buf->term_setkill("kill")')
1087endfunc
1088
1089" Run Vim, start a terminal in that Vim without the kill argument,
1090" check that :qall does not exit, :qall! does.
1091func Test_terminal_qall_exit()
1092  let after =<< trim [CODE]
1093    term
1094    let buf = bufnr("%")
1095    while term_getline(buf, 1) =~ "^\\s*$"
1096      sleep 10m
1097    endwhile
1098    set nomore
1099    au VimLeavePre * call writefile(["too early"], "Xdone")
1100    qall
1101    au! VimLeavePre * exe buf . "bwipe!" | call writefile(["done"], "Xdone")
1102    cquit
1103  [CODE]
1104
1105  if !RunVim([], after, '')
1106    return
1107  endif
1108  call assert_equal("done", readfile("Xdone")[0])
1109  call delete("Xdone")
1110endfunc
1111
1112" Run Vim in a terminal, then start a terminal in that Vim without a kill
1113" argument, check that :confirm qall works.
1114func Test_terminal_qall_prompt()
1115  CheckRunVimInTerminal
1116  let buf = RunVimInTerminal('', {})
1117
1118  " Open a terminal window and wait for the prompt to appear
1119  call term_sendkeys(buf, ":term\<CR>")
1120  call WaitForAssert({-> assert_match('\[running]', term_getline(buf, 10))})
1121  call WaitForAssert({-> assert_notmatch('^\s*$', term_getline(buf, 1))})
1122
1123  " make Vim exit, it will prompt to kill the shell
1124  call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>")
1125  call WaitForAssert({-> assert_match('ancel:', term_getline(buf, 20))})
1126  call term_sendkeys(buf, "y")
1127  call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
1128
1129  " close the terminal window where Vim was running
1130  quit
1131endfunc
1132
1133" Run Vim in a terminal, then start a terminal window with a shell and check
1134" that Vim exits if it is closed.
1135func Test_terminal_exit()
1136  CheckRunVimInTerminal
1137
1138  let lines =<< trim END
1139     let winid = win_getid()
1140     help
1141     term
1142     let termid = win_getid()
1143     call win_gotoid(winid)
1144     close
1145     call win_gotoid(termid)
1146  END
1147  call writefile(lines, 'XtermExit')
1148  let buf = RunVimInTerminal('-S XtermExit', #{rows: 10})
1149  let job = term_getjob(buf)
1150  call WaitForAssert({-> assert_equal("run", job_status(job))})
1151
1152  " quit the shell, it will make Vim exit
1153  call term_sendkeys(buf, "exit\<CR>")
1154  call WaitForAssert({-> assert_equal("dead", job_status(job))})
1155
1156  call delete('XtermExit')
1157endfunc
1158
1159func Test_terminal_open_autocmd()
1160  augroup repro
1161    au!
1162    au TerminalOpen * let s:called += 1
1163  augroup END
1164
1165  let s:called = 0
1166
1167  " Open a terminal window with :terminal
1168  terminal
1169  call assert_equal(1, s:called)
1170  bwipe!
1171
1172  " Open a terminal window with term_start()
1173  call term_start(&shell)
1174  call assert_equal(2, s:called)
1175  bwipe!
1176
1177  " Open a hidden terminal buffer with :terminal
1178  terminal ++hidden
1179  call assert_equal(3, s:called)
1180  for buf in term_list()
1181    exe buf . "bwipe!"
1182  endfor
1183
1184  " Open a hidden terminal buffer with term_start()
1185  let buf = term_start(&shell, {'hidden': 1})
1186  call assert_equal(4, s:called)
1187  exe buf . "bwipe!"
1188
1189  unlet s:called
1190  au! repro
1191endfunction
1192
1193func Check_dump01(off)
1194  call assert_equal('one two three four five', trim(getline(a:off + 1)))
1195  call assert_equal('~           Select Word', trim(getline(a:off + 7)))
1196  call assert_equal(':popup PopUp', trim(getline(a:off + 20)))
1197endfunc
1198
1199func Test_terminal_dumpwrite_composing()
1200  CheckRunVimInTerminal
1201  let save_enc = &encoding
1202  set encoding=utf-8
1203  call assert_equal(1, winnr('$'))
1204
1205  let text = " a\u0300 e\u0302 o\u0308"
1206  call writefile([text], 'Xcomposing')
1207  let buf = RunVimInTerminal('--cmd "set encoding=utf-8" Xcomposing', {})
1208  call WaitForAssert({-> assert_match(text, term_getline(buf, 1))})
1209  eval 'Xdump'->term_dumpwrite(buf)
1210  let dumpline = readfile('Xdump')[0]
1211  call assert_match('|à| |ê| |ö', dumpline)
1212
1213  call StopVimInTerminal(buf)
1214  call delete('Xcomposing')
1215  call delete('Xdump')
1216  let &encoding = save_enc
1217endfunc
1218
1219" Tests for failures in the term_dumpwrite() function
1220func Test_terminal_dumpwrite_errors()
1221  CheckRunVimInTerminal
1222  call assert_fails("call term_dumpwrite({}, 'Xtest.dump')", 'E728:')
1223  let buf = RunVimInTerminal('', {})
1224  call TermWait(buf)
1225  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump', '')", 'E715:')
1226  call assert_fails("call term_dumpwrite(buf, [])", 'E730:')
1227  call writefile([], 'Xtest.dump')
1228  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E953:')
1229  call delete('Xtest.dump')
1230  call assert_fails("call term_dumpwrite(buf, '')", 'E482:')
1231  call assert_fails("call term_dumpwrite(buf, test_null_string())", 'E482:')
1232  call test_garbagecollect_now()
1233  call StopVimInTerminal(buf)
1234  call TermWait(buf)
1235  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E958:')
1236  call assert_fails('call term_sendkeys([], ":q\<CR>")', 'E745:')
1237  call assert_equal(0, term_sendkeys(buf, ":q\<CR>"))
1238endfunc
1239
1240" just testing basic functionality.
1241func Test_terminal_dumpload()
1242  let curbuf = winbufnr('')
1243  call assert_equal(1, winnr('$'))
1244  let buf = term_dumpload('dumps/Test_popup_command_01.dump')
1245  call assert_equal(2, winnr('$'))
1246  call assert_equal(20, line('$'))
1247  call Check_dump01(0)
1248
1249  " Load another dump in the same window
1250  let buf2 = 'dumps/Test_diff_01.dump'->term_dumpload({'bufnr': buf})
1251  call assert_equal(buf, buf2)
1252  call assert_notequal('one two three four five', trim(getline(1)))
1253
1254  " Load the first dump again in the same window
1255  let buf2 = term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': buf})
1256  call assert_equal(buf, buf2)
1257  call Check_dump01(0)
1258
1259  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': curbuf})", 'E475:')
1260  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': 9999})", 'E86:')
1261  new
1262  let closedbuf = winbufnr('')
1263  quit
1264  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': closedbuf})", 'E475:')
1265  call assert_fails('call term_dumpload([])', 'E730:')
1266  call assert_fails('call term_dumpload("xabcy.dump")', 'E485:')
1267
1268  quit
1269endfunc
1270
1271func Test_terminal_dumpload_dump()
1272  CheckRunVimInTerminal
1273
1274  let lines =<< trim END
1275     call term_dumpload('dumps/Test_popupwin_22.dump', #{term_rows: 12})
1276  END
1277  call writefile(lines, 'XtermDumpload')
1278  let buf = RunVimInTerminal('-S XtermDumpload', #{rows: 15})
1279  call VerifyScreenDump(buf, 'Test_terminal_dumpload', {})
1280
1281  call StopVimInTerminal(buf)
1282  call delete('XtermDumpload')
1283endfunc
1284
1285func Test_terminal_dumpdiff()
1286  call assert_equal(1, winnr('$'))
1287  eval 'dumps/Test_popup_command_01.dump'->term_dumpdiff('dumps/Test_popup_command_02.dump')
1288  call assert_equal(2, winnr('$'))
1289  call assert_equal(62, line('$'))
1290  call Check_dump01(0)
1291  call Check_dump01(42)
1292  call assert_equal('           bbbbbbbbbbbbbbbbbb ', getline(26)[0:29])
1293  quit
1294
1295  call assert_fails('call term_dumpdiff("X1.dump", [])', 'E730:')
1296  call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:')
1297  call writefile([], 'X1.dump')
1298  call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:')
1299  call delete('X1.dump')
1300endfunc
1301
1302func Test_terminal_dumpdiff_swap()
1303  call assert_equal(1, winnr('$'))
1304  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_03.dump')
1305  call assert_equal(2, winnr('$'))
1306  call assert_equal(62, line('$'))
1307  call assert_match('Test_popup_command_01.dump', getline(21))
1308  call assert_match('Test_popup_command_03.dump', getline(42))
1309  call assert_match('Undo', getline(3))
1310  call assert_match('three four five', getline(45))
1311
1312  normal s
1313  call assert_match('Test_popup_command_03.dump', getline(21))
1314  call assert_match('Test_popup_command_01.dump', getline(42))
1315  call assert_match('three four five', getline(3))
1316  call assert_match('Undo', getline(45))
1317  quit
1318
1319  " Diff two terminal dump files with different number of rows
1320  " Swap the diffs
1321  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_winline_rnu.dump')
1322  call assert_match('Test_popup_command_01.dump', getline(21))
1323  call assert_match('Test_winline_rnu.dump', getline(42))
1324  normal s
1325  call assert_match('Test_winline_rnu.dump', getline(6))
1326  call assert_match('Test_popup_command_01.dump', getline(27))
1327  quit
1328endfunc
1329
1330func Test_terminal_dumpdiff_options()
1331  set laststatus=0
1332  call assert_equal(1, winnr('$'))
1333  let height = winheight(0)
1334  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 1, 'term_cols': 33})
1335  call assert_equal(2, winnr('$'))
1336  call assert_equal(height, winheight(winnr()))
1337  call assert_equal(33, winwidth(winnr()))
1338  call assert_equal('dump diff dumps/Test_popup_command_01.dump', bufname('%'))
1339  quit
1340
1341  call assert_equal(1, winnr('$'))
1342  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 0, 'term_rows': 13, 'term_name': 'something else'})
1343  call assert_equal(2, winnr('$'))
1344  call assert_equal(&columns, winwidth(0))
1345  call assert_equal(13, winheight(0))
1346  call assert_equal('something else', bufname('%'))
1347  quit
1348
1349  call assert_equal(1, winnr('$'))
1350  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1})
1351  call assert_equal(1, winnr('$'))
1352  call assert_fails("call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'bufnr': -1})", 'E475:')
1353  bwipe
1354
1355  set laststatus&
1356endfunc
1357
1358" When drawing the statusline the cursor position may not have been updated
1359" yet.
1360" 1. create a terminal, make it show 2 lines
1361" 2. 0.5 sec later: leave terminal window, execute "i"
1362" 3. 0.5 sec later: clear terminal window, now it's 1 line
1363" 4. 0.5 sec later: redraw, including statusline (used to trigger bug)
1364" 4. 0.5 sec later: should be done, clean up
1365func Test_terminal_statusline()
1366  CheckUnix
1367
1368  set statusline=x
1369  terminal
1370  let tbuf = bufnr('')
1371  call term_sendkeys(tbuf, "clear; echo a; echo b; sleep 1; clear\n")
1372  call timer_start(500, { tid -> feedkeys("\<C-w>j", 'tx') })
1373  call timer_start(1500, { tid -> feedkeys("\<C-l>", 'tx') })
1374  au BufLeave * if &buftype == 'terminal' | silent! normal i | endif
1375
1376  sleep 2
1377  exe tbuf . 'bwipe!'
1378  au! BufLeave
1379  set statusline=
1380endfunc
1381
1382func Api_drop_common(options)
1383  call assert_equal(1, winnr('$'))
1384
1385  " Use the title termcap entries to output the escape sequence.
1386  call writefile([
1387	\ 'set title',
1388	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1389	\ 'let &titlestring = ''["drop","Xtextfile"' . a:options . ']''',
1390	\ 'redraw',
1391	\ "set t_ts=",
1392	\ ], 'Xscript')
1393  let buf = RunVimInTerminal('-S Xscript', {})
1394  call WaitFor({-> bufnr('Xtextfile') > 0})
1395  call assert_equal('Xtextfile', expand('%:t'))
1396  call assert_true(winnr('$') >= 3)
1397  return buf
1398endfunc
1399
1400func Test_terminal_api_drop_newwin()
1401  CheckRunVimInTerminal
1402  let buf = Api_drop_common('')
1403  call assert_equal(0, &bin)
1404  call assert_equal('', &fenc)
1405
1406  call StopVimInTerminal(buf)
1407  call delete('Xscript')
1408  bwipe Xtextfile
1409endfunc
1410
1411func Test_terminal_api_drop_newwin_bin()
1412  CheckRunVimInTerminal
1413  let buf = Api_drop_common(',{"bin":1}')
1414  call assert_equal(1, &bin)
1415
1416  call StopVimInTerminal(buf)
1417  call delete('Xscript')
1418  bwipe Xtextfile
1419endfunc
1420
1421func Test_terminal_api_drop_newwin_binary()
1422  CheckRunVimInTerminal
1423  let buf = Api_drop_common(',{"binary":1}')
1424  call assert_equal(1, &bin)
1425
1426  call StopVimInTerminal(buf)
1427  call delete('Xscript')
1428  bwipe Xtextfile
1429endfunc
1430
1431func Test_terminal_api_drop_newwin_nobin()
1432  CheckRunVimInTerminal
1433  set binary
1434  let buf = Api_drop_common(',{"nobin":1}')
1435  call assert_equal(0, &bin)
1436
1437  call StopVimInTerminal(buf)
1438  call delete('Xscript')
1439  bwipe Xtextfile
1440  set nobinary
1441endfunc
1442
1443func Test_terminal_api_drop_newwin_nobinary()
1444  CheckRunVimInTerminal
1445  set binary
1446  let buf = Api_drop_common(',{"nobinary":1}')
1447  call assert_equal(0, &bin)
1448
1449  call StopVimInTerminal(buf)
1450  call delete('Xscript')
1451  bwipe Xtextfile
1452  set nobinary
1453endfunc
1454
1455func Test_terminal_api_drop_newwin_ff()
1456  CheckRunVimInTerminal
1457  let buf = Api_drop_common(',{"ff":"dos"}')
1458  call assert_equal("dos", &ff)
1459
1460  call StopVimInTerminal(buf)
1461  call delete('Xscript')
1462  bwipe Xtextfile
1463endfunc
1464
1465func Test_terminal_api_drop_newwin_fileformat()
1466  CheckRunVimInTerminal
1467  let buf = Api_drop_common(',{"fileformat":"dos"}')
1468  call assert_equal("dos", &ff)
1469
1470  call StopVimInTerminal(buf)
1471  call delete('Xscript')
1472  bwipe Xtextfile
1473endfunc
1474
1475func Test_terminal_api_drop_newwin_enc()
1476  CheckRunVimInTerminal
1477  let buf = Api_drop_common(',{"enc":"utf-16"}')
1478  call assert_equal("utf-16", &fenc)
1479
1480  call StopVimInTerminal(buf)
1481  call delete('Xscript')
1482  bwipe Xtextfile
1483endfunc
1484
1485func Test_terminal_api_drop_newwin_encoding()
1486  CheckRunVimInTerminal
1487  let buf = Api_drop_common(',{"encoding":"utf-16"}')
1488  call assert_equal("utf-16", &fenc)
1489
1490  call StopVimInTerminal(buf)
1491  call delete('Xscript')
1492  bwipe Xtextfile
1493endfunc
1494
1495func Test_terminal_api_drop_oldwin()
1496  CheckRunVimInTerminal
1497  let firstwinid = win_getid()
1498  split Xtextfile
1499  let textfile_winid = win_getid()
1500  call assert_equal(2, winnr('$'))
1501  call win_gotoid(firstwinid)
1502
1503  " Use the title termcap entries to output the escape sequence.
1504  call writefile([
1505	\ 'set title',
1506	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1507	\ 'let &titlestring = ''["drop","Xtextfile"]''',
1508	\ 'redraw',
1509	\ "set t_ts=",
1510	\ ], 'Xscript')
1511  let buf = RunVimInTerminal('-S Xscript', {'rows': 10})
1512  call WaitForAssert({-> assert_equal('Xtextfile', expand('%:t'))})
1513  call assert_equal(textfile_winid, win_getid())
1514
1515  call StopVimInTerminal(buf)
1516  call delete('Xscript')
1517  bwipe Xtextfile
1518endfunc
1519
1520func Tapi_TryThis(bufnum, arg)
1521  let g:called_bufnum = a:bufnum
1522  let g:called_arg = a:arg
1523endfunc
1524
1525func WriteApiCall(funcname)
1526  " Use the title termcap entries to output the escape sequence.
1527  call writefile([
1528	\ 'set title',
1529	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1530	\ 'let &titlestring = ''["call","' . a:funcname . '",["hello",123]]''',
1531	\ 'redraw',
1532	\ "set t_ts=",
1533	\ ], 'Xscript')
1534endfunc
1535
1536func Test_terminal_api_call()
1537  CheckRunVimInTerminal
1538
1539  unlet! g:called_bufnum
1540  unlet! g:called_arg
1541
1542  call WriteApiCall('Tapi_TryThis')
1543
1544  " Default
1545  let buf = RunVimInTerminal('-S Xscript', {})
1546  call WaitFor({-> exists('g:called_bufnum')})
1547  call assert_equal(buf, g:called_bufnum)
1548  call assert_equal(['hello', 123], g:called_arg)
1549  call StopVimInTerminal(buf)
1550
1551  unlet! g:called_bufnum
1552  unlet! g:called_arg
1553
1554  " Enable explicitly
1555  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'Tapi_Try'})
1556  call WaitFor({-> exists('g:called_bufnum')})
1557  call assert_equal(buf, g:called_bufnum)
1558  call assert_equal(['hello', 123], g:called_arg)
1559  call StopVimInTerminal(buf)
1560
1561  unlet! g:called_bufnum
1562  unlet! g:called_arg
1563
1564  func! ApiCall_TryThis(bufnum, arg)
1565    let g:called_bufnum2 = a:bufnum
1566    let g:called_arg2 = a:arg
1567  endfunc
1568
1569  call WriteApiCall('ApiCall_TryThis')
1570
1571  " Use prefix match
1572  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'ApiCall_'})
1573  call WaitFor({-> exists('g:called_bufnum2')})
1574  call assert_equal(buf, g:called_bufnum2)
1575  call assert_equal(['hello', 123], g:called_arg2)
1576  call StopVimInTerminal(buf)
1577
1578  call assert_fails("call term_start('ls', {'term_api' : []})", 'E730:')
1579
1580  unlet! g:called_bufnum2
1581  unlet! g:called_arg2
1582
1583  call delete('Xscript')
1584  delfunction! ApiCall_TryThis
1585  unlet! g:called_bufnum2
1586  unlet! g:called_arg2
1587endfunc
1588
1589func Test_terminal_api_call_fails()
1590  CheckRunVimInTerminal
1591
1592  func! TryThis(bufnum, arg)
1593    let g:called_bufnum3 = a:bufnum
1594    let g:called_arg3 = a:arg
1595  endfunc
1596
1597  call WriteApiCall('TryThis')
1598
1599  unlet! g:called_bufnum3
1600  unlet! g:called_arg3
1601
1602  " Not permitted
1603  call ch_logfile('Xlog', 'w')
1604  let buf = RunVimInTerminal('-S Xscript', {'term_api': ''})
1605  call WaitForAssert({-> assert_match('Unpermitted function: TryThis', string(readfile('Xlog')))})
1606  call assert_false(exists('g:called_bufnum3'))
1607  call assert_false(exists('g:called_arg3'))
1608  call StopVimInTerminal(buf)
1609
1610  " No match
1611  call ch_logfile('Xlog', 'w')
1612  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'TryThat'})
1613  call WaitFor({-> string(readfile('Xlog')) =~ 'Unpermitted function: TryThis'})
1614  call assert_false(exists('g:called_bufnum3'))
1615  call assert_false(exists('g:called_arg3'))
1616  call StopVimInTerminal(buf)
1617
1618  call delete('Xscript')
1619  call ch_logfile('')
1620  call delete('Xlog')
1621  delfunction! TryThis
1622  unlet! g:called_bufnum3
1623  unlet! g:called_arg3
1624endfunc
1625
1626let s:caught_e937 = 0
1627
1628func Tapi_Delete(bufnum, arg)
1629  try
1630    execute 'bdelete!' a:bufnum
1631  catch /E937:/
1632    let s:caught_e937 = 1
1633  endtry
1634endfunc
1635
1636func Test_terminal_api_call_fail_delete()
1637  CheckRunVimInTerminal
1638
1639  call WriteApiCall('Tapi_Delete')
1640  let buf = RunVimInTerminal('-S Xscript', {})
1641  call WaitForAssert({-> assert_equal(1, s:caught_e937)})
1642
1643  call StopVimInTerminal(buf)
1644  call delete('Xscript')
1645  call ch_logfile('', '')
1646endfunc
1647
1648func Test_terminal_setapi_and_call()
1649  CheckRunVimInTerminal
1650
1651  call WriteApiCall('Tapi_TryThis')
1652  call ch_logfile('Xlog', 'w')
1653
1654  unlet! g:called_bufnum
1655  unlet! g:called_arg
1656
1657  let buf = RunVimInTerminal('-S Xscript', {'term_api': ''})
1658  call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))})
1659  call assert_false(exists('g:called_bufnum'))
1660  call assert_false(exists('g:called_arg'))
1661
1662  eval buf->term_setapi('Tapi_')
1663  call term_sendkeys(buf, ":set notitle\<CR>")
1664  call term_sendkeys(buf, ":source Xscript\<CR>")
1665  call WaitFor({-> exists('g:called_bufnum')})
1666  call assert_equal(buf, g:called_bufnum)
1667  call assert_equal(['hello', 123], g:called_arg)
1668
1669  call StopVimInTerminal(buf)
1670
1671  call delete('Xscript')
1672  call ch_logfile('')
1673  call delete('Xlog')
1674  unlet! g:called_bufnum
1675  unlet! g:called_arg
1676endfunc
1677
1678func Test_terminal_api_arg()
1679  CheckRunVimInTerminal
1680
1681  call WriteApiCall('Tapi_TryThis')
1682  call ch_logfile('Xlog', 'w')
1683
1684  unlet! g:called_bufnum
1685  unlet! g:called_arg
1686
1687  execute 'term ++api= ' .. GetVimCommandCleanTerm() .. '-S Xscript'
1688  let buf = bufnr('%')
1689  call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))})
1690  call assert_false(exists('g:called_bufnum'))
1691  call assert_false(exists('g:called_arg'))
1692
1693  call StopVimInTerminal(buf)
1694
1695  call ch_logfile('Xlog', 'w')
1696
1697  execute 'term ++api=Tapi_ ' .. GetVimCommandCleanTerm() .. '-S Xscript'
1698  let buf = bufnr('%')
1699  call WaitFor({-> exists('g:called_bufnum')})
1700  call assert_equal(buf, g:called_bufnum)
1701  call assert_equal(['hello', 123], g:called_arg)
1702
1703  call StopVimInTerminal(buf)
1704
1705  call delete('Xscript')
1706  call ch_logfile('')
1707  call delete('Xlog')
1708  unlet! g:called_bufnum
1709  unlet! g:called_arg
1710endfunc
1711
1712func Test_terminal_ansicolors_default()
1713  CheckFunction term_getansicolors
1714
1715  let colors = [
1716	\ '#000000', '#e00000',
1717	\ '#00e000', '#e0e000',
1718	\ '#0000e0', '#e000e0',
1719	\ '#00e0e0', '#e0e0e0',
1720	\ '#808080', '#ff4040',
1721	\ '#40ff40', '#ffff40',
1722	\ '#4040ff', '#ff40ff',
1723	\ '#40ffff', '#ffffff',
1724	\]
1725
1726  let buf = Run_shell_in_terminal({})
1727  call assert_equal(colors, term_getansicolors(buf))
1728  call StopShellInTerminal(buf)
1729  call TermWait(buf)
1730  call assert_equal([], term_getansicolors(buf))
1731
1732  exe buf . 'bwipe'
1733endfunc
1734
1735let s:test_colors = [
1736	\ '#616e64', '#0d0a79',
1737	\ '#6d610d', '#0a7373',
1738	\ '#690d0a', '#6d696e',
1739	\ '#0d0a6f', '#616e0d',
1740	\ '#0a6479', '#6d0d0a',
1741	\ '#617373', '#0d0a69',
1742	\ '#6d690d', '#0a6e6f',
1743	\ '#610d0a', '#6e6479',
1744	\]
1745
1746func Test_terminal_ansicolors_global()
1747  CheckFeature termguicolors
1748  CheckFunction term_getansicolors
1749
1750  let g:terminal_ansi_colors = reverse(copy(s:test_colors))
1751  let buf = Run_shell_in_terminal({})
1752  call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
1753  call StopShellInTerminal(buf)
1754  call TermWait(buf)
1755
1756  exe buf . 'bwipe'
1757  unlet g:terminal_ansi_colors
1758endfunc
1759
1760func Test_terminal_ansicolors_func()
1761  CheckFeature termguicolors
1762  CheckFunction term_getansicolors
1763
1764  let g:terminal_ansi_colors = reverse(copy(s:test_colors))
1765  let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors})
1766  call assert_equal(s:test_colors, term_getansicolors(buf))
1767
1768  call term_setansicolors(buf, g:terminal_ansi_colors)
1769  call assert_equal(g:terminal_ansi_colors, buf->term_getansicolors())
1770
1771  let colors = [
1772	\ 'ivory', 'AliceBlue',
1773	\ 'grey67', 'dark goldenrod',
1774	\ 'SteelBlue3', 'PaleVioletRed4',
1775	\ 'MediumPurple2', 'yellow2',
1776	\ 'RosyBrown3', 'OrangeRed2',
1777	\ 'white smoke', 'navy blue',
1778	\ 'grey47', 'gray97',
1779	\ 'MistyRose2', 'DodgerBlue4',
1780	\]
1781  eval buf->term_setansicolors(colors)
1782
1783  let colors[4] = 'Invalid'
1784  call assert_fails('call term_setansicolors(buf, colors)', 'E254:')
1785  call assert_fails('call term_setansicolors(buf, {})', 'E714:')
1786
1787  call StopShellInTerminal(buf)
1788  call TermWait(buf)
1789  call assert_equal(0, term_setansicolors(buf, []))
1790  exe buf . 'bwipe'
1791endfunc
1792
1793func Test_terminal_all_ansi_colors()
1794  CheckRunVimInTerminal
1795
1796  " Use all the ANSI colors.
1797  call writefile([
1798	\ 'call setline(1, "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPP XXYYZZ")',
1799	\ 'hi Tblack ctermfg=0 ctermbg=8',
1800	\ 'hi Tdarkred ctermfg=1 ctermbg=9',
1801	\ 'hi Tdarkgreen ctermfg=2 ctermbg=10',
1802	\ 'hi Tbrown ctermfg=3 ctermbg=11',
1803	\ 'hi Tdarkblue ctermfg=4 ctermbg=12',
1804	\ 'hi Tdarkmagenta ctermfg=5 ctermbg=13',
1805	\ 'hi Tdarkcyan ctermfg=6 ctermbg=14',
1806	\ 'hi Tlightgrey ctermfg=7 ctermbg=15',
1807	\ 'hi Tdarkgrey ctermfg=8 ctermbg=0',
1808	\ 'hi Tred ctermfg=9 ctermbg=1',
1809	\ 'hi Tgreen ctermfg=10 ctermbg=2',
1810	\ 'hi Tyellow ctermfg=11 ctermbg=3',
1811	\ 'hi Tblue ctermfg=12 ctermbg=4',
1812	\ 'hi Tmagenta ctermfg=13 ctermbg=5',
1813	\ 'hi Tcyan ctermfg=14 ctermbg=6',
1814	\ 'hi Twhite ctermfg=15 ctermbg=7',
1815	\ 'hi TdarkredBold ctermfg=1 cterm=bold',
1816	\ 'hi TgreenBold ctermfg=10 cterm=bold',
1817	\ 'hi TmagentaBold ctermfg=13 cterm=bold ctermbg=5',
1818	\ '',
1819	\ 'call  matchadd("Tblack", "A")',
1820	\ 'call  matchadd("Tdarkred", "B")',
1821	\ 'call  matchadd("Tdarkgreen", "C")',
1822	\ 'call  matchadd("Tbrown", "D")',
1823	\ 'call  matchadd("Tdarkblue", "E")',
1824	\ 'call  matchadd("Tdarkmagenta", "F")',
1825	\ 'call  matchadd("Tdarkcyan", "G")',
1826	\ 'call  matchadd("Tlightgrey", "H")',
1827	\ 'call  matchadd("Tdarkgrey", "I")',
1828	\ 'call  matchadd("Tred", "J")',
1829	\ 'call  matchadd("Tgreen", "K")',
1830	\ 'call  matchadd("Tyellow", "L")',
1831	\ 'call  matchadd("Tblue", "M")',
1832	\ 'call  matchadd("Tmagenta", "N")',
1833	\ 'call  matchadd("Tcyan", "O")',
1834	\ 'call  matchadd("Twhite", "P")',
1835	\ 'call  matchadd("TdarkredBold", "X")',
1836	\ 'call  matchadd("TgreenBold", "Y")',
1837	\ 'call  matchadd("TmagentaBold", "Z")',
1838	\ 'redraw',
1839	\ ], 'Xcolorscript')
1840  let buf = RunVimInTerminal('-S Xcolorscript', {'rows': 10})
1841  call VerifyScreenDump(buf, 'Test_terminal_all_ansi_colors', {})
1842
1843  call term_sendkeys(buf, ":q\<CR>")
1844  call StopVimInTerminal(buf)
1845  call delete('Xcolorscript')
1846endfunc
1847
1848
1849" vim: shiftwidth=2 sts=2 expandtab
1850