1" Tests for the terminal window.
2
3source check.vim
4CheckFeature terminal
5
6source shared.vim
7source screendump.vim
8source mouse.vim
9
10let s:python = PythonProg()
11let $PROMPT_COMMAND=''
12
13" Open a terminal with a shell, assign the job to g:job and return the buffer
14" number.
15func Run_shell_in_terminal(options)
16  if has('win32')
17    let buf = term_start([&shell,'/k'], a:options)
18  else
19    let buf = term_start(&shell, a:options)
20  endif
21  let g:test_is_flaky = 1
22
23  let termlist = term_list()
24  call assert_equal(1, len(termlist))
25  call assert_equal(buf, termlist[0])
26
27  let g:job = term_getjob(buf)
28  call assert_equal(v:t_job, type(g:job))
29
30  let string = string({'job': buf->term_getjob()})
31  call assert_match("{'job': 'process \\d\\+ run'}", string)
32
33  return buf
34endfunc
35
36func Test_terminal_basic()
37  au TerminalOpen * let b:done = 'yes'
38  let buf = Run_shell_in_terminal({})
39
40  call assert_equal('t', mode())
41  call assert_equal('yes', b:done)
42  call assert_match('%aR[^\n]*running]', execute('ls'))
43  call assert_match('%aR[^\n]*running]', execute('ls R'))
44  call assert_notmatch('%[^\n]*running]', execute('ls F'))
45  call assert_notmatch('%[^\n]*running]', execute('ls ?'))
46  call assert_fails('set modifiable', 'E946:')
47
48  call StopShellInTerminal(buf)
49  call TermWait(buf)
50  call assert_equal('n', mode())
51  call assert_match('%aF[^\n]*finished]', execute('ls'))
52  call assert_match('%aF[^\n]*finished]', execute('ls F'))
53  call assert_notmatch('%[^\n]*finished]', execute('ls R'))
54  call assert_notmatch('%[^\n]*finished]', execute('ls ?'))
55
56  " closing window wipes out the terminal buffer a with finished job
57  close
58  call assert_equal("", bufname(buf))
59
60  au! TerminalOpen
61  unlet g:job
62endfunc
63
64func Test_terminal_TerminalWinOpen()
65  au TerminalWinOpen * let b:done = 'yes'
66  let buf = Run_shell_in_terminal({})
67  call assert_equal('yes', b:done)
68  call StopShellInTerminal(buf)
69  " closing window wipes out the terminal buffer with the finished job
70  close
71
72  if has("unix")
73    terminal ++hidden ++open sleep 1
74    sleep 1
75    call assert_fails("echo b:done", 'E121:')
76  endif
77
78  au! TerminalWinOpen
79endfunc
80
81func Test_terminal_make_change()
82  let buf = Run_shell_in_terminal({})
83  call StopShellInTerminal(buf)
84  call TermWait(buf)
85
86  setlocal modifiable
87  exe "normal Axxx\<Esc>"
88  call assert_fails(buf . 'bwipe', 'E517')
89  undo
90
91  exe buf . 'bwipe'
92  unlet g:job
93endfunc
94
95func Test_terminal_paste_register()
96  let @" = "text to paste"
97
98  let buf = Run_shell_in_terminal({})
99  " Wait for the shell to display a prompt
100  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
101
102  call feedkeys("echo \<C-W>\"\" \<C-W>\"=37 + 5\<CR>\<CR>", 'xt')
103  call WaitForAssert({-> assert_match("echo text to paste 42$", getline(1))})
104  call WaitForAssert({-> assert_equal('text to paste 42',       2->getline())})
105
106  exe buf . 'bwipe!'
107  unlet g:job
108endfunc
109
110func Test_terminal_wipe_buffer()
111  let buf = Run_shell_in_terminal({})
112  call assert_fails(buf . 'bwipe', 'E517')
113  exe buf . 'bwipe!'
114  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
115  call assert_equal("", bufname(buf))
116
117  unlet g:job
118endfunc
119
120func Test_terminal_split_quit()
121  let buf = Run_shell_in_terminal({})
122  call TermWait(buf)
123  split
124  quit!
125  call TermWait(buf)
126  sleep 50m
127  call assert_equal('run', job_status(g:job))
128
129  quit!
130  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
131
132  exe buf . 'bwipe'
133  unlet g:job
134endfunc
135
136func Test_terminal_hide_buffer()
137  let buf = Run_shell_in_terminal({})
138  setlocal bufhidden=hide
139  quit
140  for nr in range(1, winnr('$'))
141    call assert_notequal(winbufnr(nr), buf)
142  endfor
143  call assert_true(bufloaded(buf))
144  call assert_true(buflisted(buf))
145
146  exe 'split ' . buf . 'buf'
147  call StopShellInTerminal(buf)
148  exe buf . 'bwipe'
149
150  unlet g:job
151endfunc
152
153func s:Nasty_exit_cb(job, st)
154  exe g:buf . 'bwipe!'
155  let g:buf = 0
156endfunc
157
158func Get_cat_123_cmd()
159  if has('win32')
160    if !has('conpty')
161      return 'cmd /c "cls && color 2 && echo 123"'
162    else
163      " When clearing twice, extra sequence is not output.
164      return 'cmd /c "cls && cls && color 2 && echo 123"'
165    endif
166  else
167    call writefile(["\<Esc>[32m123"], 'Xtext')
168    return "cat Xtext"
169  endif
170endfunc
171
172func Test_terminal_nasty_cb()
173  let cmd = Get_cat_123_cmd()
174  let g:buf = term_start(cmd, {'exit_cb': function('s:Nasty_exit_cb')})
175  let g:job = term_getjob(g:buf)
176
177  call WaitForAssert({-> assert_equal("dead", job_status(g:job))})
178  call WaitForAssert({-> assert_equal(0, g:buf)})
179  unlet g:job
180  unlet g:buf
181  call delete('Xtext')
182endfunc
183
184func Check_123(buf)
185  let l = term_scrape(a:buf, 0)
186  call assert_true(len(l) == 0)
187  let l = term_scrape(a:buf, 999)
188  call assert_true(len(l) == 0)
189  let l = a:buf->term_scrape(1)
190  call assert_true(len(l) > 0)
191  call assert_equal('1', l[0].chars)
192  call assert_equal('2', l[1].chars)
193  call assert_equal('3', l[2].chars)
194  call assert_equal('#00e000', l[0].fg)
195  call assert_equal(0, term_getattr(l[0].attr, 'bold'))
196  call assert_equal(0, l[0].attr->term_getattr('italic'))
197  if has('win32')
198    " On Windows 'background' always defaults to dark, even though the terminal
199    " may use a light background.  Therefore accept both white and black.
200    call assert_match('#ffffff\|#000000', l[0].bg)
201  else
202    if &background == 'light'
203      call assert_equal('#ffffff', l[0].bg)
204    else
205      call assert_equal('#000000', l[0].bg)
206    endif
207  endif
208
209  let l = term_getline(a:buf, -1)
210  call assert_equal('', l)
211  let l = term_getline(a:buf, 0)
212  call assert_equal('', l)
213  let l = term_getline(a:buf, 999)
214  call assert_equal('', l)
215  let l = term_getline(a:buf, 1)
216  call assert_equal('123', l)
217endfunc
218
219func Test_terminal_scrape_123()
220  let cmd = Get_cat_123_cmd()
221  let buf = term_start(cmd)
222
223  let termlist = term_list()
224  call assert_equal(1, len(termlist))
225  call assert_equal(buf, termlist[0])
226
227  " Nothing happens with invalid buffer number
228  call term_wait(1234)
229
230  call TermWait(buf)
231  " On MS-Windows we first get a startup message of two lines, wait for the
232  " "cls" to happen, after that we have one line with three characters.
233  call WaitForAssert({-> assert_equal(3, len(term_scrape(buf, 1)))})
234  call Check_123(buf)
235
236  " Must still work after the job ended.
237  let job = term_getjob(buf)
238  call WaitForAssert({-> assert_equal("dead", job_status(job))})
239  call TermWait(buf)
240  call Check_123(buf)
241
242  exe buf . 'bwipe'
243  call delete('Xtext')
244endfunc
245
246func Test_terminal_scrape_multibyte()
247  call writefile(["léttまrs"], 'Xtext')
248  if has('win32')
249    " Run cmd with UTF-8 codepage to make the type command print the expected
250    " multibyte characters.
251    let buf = term_start("cmd /K chcp 65001")
252    call term_sendkeys(buf, "type Xtext\<CR>")
253    eval buf->term_sendkeys("exit\<CR>")
254    let line = 4
255  else
256    let buf = term_start("cat Xtext")
257    let line = 1
258  endif
259
260  call WaitFor({-> len(term_scrape(buf, line)) >= 7 && term_scrape(buf, line)[0].chars == "l"})
261  let l = term_scrape(buf, line)
262  call assert_true(len(l) >= 7)
263  call assert_equal('l', l[0].chars)
264  call assert_equal('é', l[1].chars)
265  call assert_equal(1, l[1].width)
266  call assert_equal('t', l[2].chars)
267  call assert_equal('t', l[3].chars)
268  call assert_equal('ま', l[4].chars)
269  call assert_equal(2, l[4].width)
270  call assert_equal('r', l[5].chars)
271  call assert_equal('s', l[6].chars)
272
273  let job = term_getjob(buf)
274  call WaitForAssert({-> assert_equal("dead", job_status(job))})
275  call TermWait(buf)
276
277  exe buf . 'bwipe'
278  call delete('Xtext')
279endfunc
280
281func Test_terminal_scroll()
282  call writefile(range(1, 200), 'Xtext')
283  if has('win32')
284    let cmd = 'cmd /c "type Xtext"'
285  else
286    let cmd = "cat Xtext"
287  endif
288  let buf = term_start(cmd)
289
290  let job = term_getjob(buf)
291  call WaitForAssert({-> assert_equal("dead", job_status(job))})
292  call TermWait(buf)
293
294  " wait until the scrolling stops
295  while 1
296    let scrolled = buf->term_getscrolled()
297    sleep 20m
298    if scrolled == buf->term_getscrolled()
299      break
300    endif
301  endwhile
302
303  call assert_equal('1', getline(1))
304  call assert_equal('1', term_getline(buf, 1 - scrolled))
305  call assert_equal('49', getline(49))
306  call assert_equal('49', term_getline(buf, 49 - scrolled))
307  call assert_equal('200', getline(200))
308  call assert_equal('200', term_getline(buf, 200 - scrolled))
309
310  exe buf . 'bwipe'
311  call delete('Xtext')
312endfunc
313
314func Test_terminal_scrollback()
315  let buf = Run_shell_in_terminal({'term_rows': 15})
316  set termwinscroll=100
317  call writefile(range(150), 'Xtext')
318  if has('win32')
319    call term_sendkeys(buf, "type Xtext\<CR>")
320  else
321    call term_sendkeys(buf, "cat Xtext\<CR>")
322  endif
323  let rows = term_getsize(buf)[0]
324  " On MS-Windows there is an empty line, check both last line and above it.
325  call WaitForAssert({-> assert_match( '149', term_getline(buf, rows - 1) . term_getline(buf, rows - 2))})
326  let lines = line('$')
327  call assert_inrange(91, 100, lines)
328
329  call StopShellInTerminal(buf)
330  call TermWait(buf)
331  exe buf . 'bwipe'
332  set termwinscroll&
333  call delete('Xtext')
334endfunc
335
336func Test_terminal_postponed_scrollback()
337  " tail -f only works on Unix
338  CheckUnix
339
340  call writefile(range(50), 'Xtext')
341  call writefile([
342	\ 'set shell=/bin/sh noruler',
343	\ 'terminal',
344	\ 'sleep 200m',
345	\ 'call feedkeys("tail -n 100 -f Xtext\<CR>", "xt")',
346	\ 'sleep 100m',
347	\ 'call feedkeys("\<C-W>N", "xt")',
348	\ ], 'XTest_postponed')
349  let buf = RunVimInTerminal('-S XTest_postponed', {})
350  " Check that the Xtext lines are displayed and in Terminal-Normal mode
351  call VerifyScreenDump(buf, 'Test_terminal_scrollback_1', {})
352
353  silent !echo 'one more line' >>Xtext
354  " Screen will not change, move cursor to get a different dump
355  call term_sendkeys(buf, "k")
356  call VerifyScreenDump(buf, 'Test_terminal_scrollback_2', {})
357
358  " Back to Terminal-Job mode, text will scroll and show the extra line.
359  call term_sendkeys(buf, "a")
360  call VerifyScreenDump(buf, 'Test_terminal_scrollback_3', {})
361
362  " stop "tail -f"
363  call term_sendkeys(buf, "\<C-C>")
364  call TermWait(buf, 25)
365  " stop shell
366  call term_sendkeys(buf, "exit\<CR>")
367  call TermWait(buf, 50)
368  " close terminal window
369  let tsk_ret = term_sendkeys(buf, ":q\<CR>")
370
371  " check type of term_sendkeys() return value
372  echo type(tsk_ret)
373
374  call StopVimInTerminal(buf)
375  call delete('XTest_postponed')
376  call delete('Xtext')
377endfunc
378
379" Run diff on two dumps with different size.
380func Test_terminal_dumpdiff_size()
381  call assert_equal(1, winnr('$'))
382  call term_dumpdiff('dumps/Test_incsearch_search_01.dump', 'dumps/Test_popup_command_01.dump')
383  call assert_equal(2, winnr('$'))
384  call assert_match('Test_incsearch_search_01.dump', getline(10))
385  call assert_match('      +++++$', getline(11))
386  call assert_match('Test_popup_command_01.dump', getline(31))
387  call assert_equal(repeat('+', 75), getline(30))
388  quit
389endfunc
390
391func Test_terminal_size()
392  let cmd = Get_cat_123_cmd()
393
394  exe 'terminal ++rows=5 ' . cmd
395  let size = term_getsize('')
396  bwipe!
397  call assert_equal(5, size[0])
398
399  call term_start(cmd, {'term_rows': 6})
400  let size = term_getsize('')
401  bwipe!
402  call assert_equal(6, size[0])
403
404  vsplit
405  exe 'terminal ++rows=5 ++cols=33 ' . cmd
406  call assert_equal([5, 33], ''->term_getsize())
407
408  call term_setsize('', 6, 0)
409  call assert_equal([6, 33], term_getsize(''))
410
411  eval ''->term_setsize(0, 35)
412  call assert_equal([6, 35], term_getsize(''))
413
414  call term_setsize('', 7, 30)
415  call assert_equal([7, 30], term_getsize(''))
416
417  bwipe!
418  call assert_fails("call term_setsize('', 7, 30)", "E955:")
419
420  call term_start(cmd, {'term_rows': 6, 'term_cols': 36})
421  let size = term_getsize('')
422  bwipe!
423  call assert_equal([6, 36], size)
424
425  exe 'vertical terminal ++cols=20 ' . cmd
426  let size = term_getsize('')
427  bwipe!
428  call assert_equal(20, size[1])
429
430  eval cmd->term_start({'vertical': 1, 'term_cols': 26})
431  let size = term_getsize('')
432  bwipe!
433  call assert_equal(26, size[1])
434
435  split
436  exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd
437  let size = term_getsize('')
438  bwipe!
439  call assert_equal([6, 20], size)
440
441  call term_start(cmd, {'vertical': 1, 'term_rows': 7, 'term_cols': 27})
442  let size = term_getsize('')
443  bwipe!
444  call assert_equal([7, 27], size)
445
446  call delete('Xtext')
447endfunc
448
449func Test_terminal_curwin()
450  let cmd = Get_cat_123_cmd()
451  call assert_equal(1, winnr('$'))
452
453  split dummy
454  exe 'terminal ++curwin ' . cmd
455  call assert_equal(2, winnr('$'))
456  bwipe!
457
458  split dummy
459  call term_start(cmd, {'curwin': 1})
460  call assert_equal(2, winnr('$'))
461  bwipe!
462
463  split dummy
464  call setline(1, 'change')
465  call assert_fails('terminal ++curwin ' . cmd, 'E37:')
466  call assert_equal(2, winnr('$'))
467  exe 'terminal! ++curwin ' . cmd
468  call assert_equal(2, winnr('$'))
469  bwipe!
470
471  split dummy
472  call setline(1, 'change')
473  call assert_fails("call term_start(cmd, {'curwin': 1})", 'E37:')
474  call assert_equal(2, winnr('$'))
475  bwipe!
476
477  split dummy
478  bwipe!
479  call delete('Xtext')
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', '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  call delete('Xfile')
827  bwipe
828
829  if has('unix')
830    call writefile(['one line'], 'Xfile')
831    let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
832    call TermWait(buf)
833    call WaitForAssert({-> assert_equal('one line', term_getline(buf, 1))})
834    let g:job = term_getjob(buf)
835    call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
836    bwipe
837    call delete('Xfile')
838  endif
839endfunc
840
841func TerminalTmap(remap)
842  let buf = Run_shell_in_terminal({})
843  call assert_equal('t', mode())
844
845  if a:remap
846    tmap 123 456
847  else
848    tnoremap 123 456
849  endif
850  " don't use abcde, it's an existing command
851  tmap 456 abxde
852  call assert_equal('456', maparg('123', 't'))
853  call assert_equal('abxde', maparg('456', 't'))
854  call feedkeys("123", 'tx')
855  call WaitForAssert({-> assert_match('abxde\|456', term_getline(buf, term_getcursor(buf)[0]))})
856  let lnum = term_getcursor(buf)[0]
857  if a:remap
858    call assert_match('abxde', term_getline(buf, lnum))
859  else
860    call assert_match('456', term_getline(buf, lnum))
861  endif
862
863  call term_sendkeys(buf, "\r")
864  call StopShellInTerminal(buf)
865  call TermWait(buf)
866
867  tunmap 123
868  tunmap 456
869  call assert_equal('', maparg('123', 't'))
870  close
871  unlet g:job
872endfunc
873
874func Test_terminal_tmap()
875  call TerminalTmap(1)
876  call TerminalTmap(0)
877endfunc
878
879func Test_terminal_wall()
880  let buf = Run_shell_in_terminal({})
881  wall
882  call StopShellInTerminal(buf)
883  call TermWait(buf)
884  exe buf . 'bwipe'
885  unlet g:job
886endfunc
887
888func Test_terminal_wqall()
889  let buf = Run_shell_in_terminal({})
890  call assert_fails('wqall', 'E948')
891  call StopShellInTerminal(buf)
892  call TermWait(buf)
893  exe buf . 'bwipe'
894  unlet g:job
895endfunc
896
897func Test_terminal_composing_unicode()
898  let save_enc = &encoding
899  set encoding=utf-8
900
901  if has('win32')
902    let cmd = "cmd /K chcp 65001"
903    let lnum = [3, 6, 9]
904  else
905    let cmd = &shell
906    let lnum = [1, 3, 5]
907  endif
908
909  enew
910  let buf = term_start(cmd, {'curwin': bufnr('')})
911  let g:job = term_getjob(buf)
912  call WaitFor({-> term_getline(buf, 1) !=# ''}, 1000)
913
914  if has('win32')
915    call assert_equal('cmd', job_info(g:job).cmd[0])
916  else
917    call assert_equal(&shell, job_info(g:job).cmd[0])
918  endif
919
920  " ascii + composing
921  let txt = "a\u0308bc"
922  call term_sendkeys(buf, "echo " . txt)
923  call TermWait(buf, 25)
924  call assert_match("echo " . txt, term_getline(buf, lnum[0]))
925  call term_sendkeys(buf, "\<cr>")
926  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[0] + 1))}, 1000)
927  let l = term_scrape(buf, lnum[0] + 1)
928  call assert_equal("a\u0308", l[0].chars)
929  call assert_equal("b", l[1].chars)
930  call assert_equal("c", l[2].chars)
931
932  " multibyte + composing
933  let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099"
934  call term_sendkeys(buf, "echo " . txt)
935  call TermWait(buf, 25)
936  call assert_match("echo " . txt, term_getline(buf, lnum[1]))
937  call term_sendkeys(buf, "\<cr>")
938  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[1] + 1))}, 1000)
939  let l = term_scrape(buf, lnum[1] + 1)
940  call assert_equal("\u304b\u3099", l[0].chars)
941  call assert_equal("\u304e", l[2].chars)
942  call assert_equal("\u304f\u3099", l[3].chars)
943  call assert_equal("\u3052", l[5].chars)
944  call assert_equal("\u3053\u3099", l[6].chars)
945
946  " \u00a0 + composing
947  let txt = "abc\u00a0\u0308"
948  call term_sendkeys(buf, "echo " . txt)
949  call TermWait(buf, 25)
950  call assert_match("echo " . txt, term_getline(buf, lnum[2]))
951  call term_sendkeys(buf, "\<cr>")
952  call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[2] + 1))}, 1000)
953  let l = term_scrape(buf, lnum[2] + 1)
954  call assert_equal("\u00a0\u0308", l[3].chars)
955
956  call term_sendkeys(buf, "exit\r")
957  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
958  bwipe!
959  unlet g:job
960  let &encoding = save_enc
961endfunc
962
963func Test_terminal_aucmd_on_close()
964  fun Nop()
965    let s:called = 1
966  endfun
967
968  aug repro
969      au!
970      au BufWinLeave * call Nop()
971  aug END
972
973  let [cmd, waittime] = s:get_sleep_cmd()
974
975  call assert_equal(1, winnr('$'))
976  new
977  call setline(1, ['one', 'two'])
978  exe 'term ++close ' . cmd
979  wincmd p
980  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
981  call assert_equal(1, s:called)
982  bwipe!
983
984  unlet s:called
985  au! repro
986  delfunc Nop
987endfunc
988
989func Test_terminal_term_start_empty_command()
990  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
991  call assert_fails(cmd, 'E474')
992  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
993  call assert_fails(cmd, 'E474')
994  let cmd = "call term_start({}, {'curwin' : 1, 'term_finish' : 'close'})"
995  call assert_fails(cmd, 'E474')
996  let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})"
997  call assert_fails(cmd, 'E474')
998  let cmd = "call term_start('', {'term_name' : []})"
999  call assert_fails(cmd, 'E475')
1000  let cmd = "call term_start('', {'term_finish' : 'axby'})"
1001  call assert_fails(cmd, 'E475')
1002  let cmd = "call term_start('', {'eof_chars' : []})"
1003  call assert_fails(cmd, 'E475:')
1004  let cmd = "call term_start('', {'term_kill' : []})"
1005  call assert_fails(cmd, 'E475:')
1006  let cmd = "call term_start('', {'tty_type' : []})"
1007  call assert_fails(cmd, 'E475:')
1008  let cmd = "call term_start('', {'tty_type' : 'abc'})"
1009  call assert_fails(cmd, 'E475:')
1010  let cmd = "call term_start('', {'term_highlight' : []})"
1011  call assert_fails(cmd, 'E475:')
1012  if has('gui')
1013    let cmd = "call term_start('', {'ansi_colors' : 'abc'})"
1014    call assert_fails(cmd, 'E475:')
1015    let cmd = "call term_start('', {'ansi_colors' : [[]]})"
1016    call assert_fails(cmd, 'E730:')
1017    let cmd = "call term_start('', {'ansi_colors' : repeat(['blue'], 18)})"
1018    call assert_fails(cmd, 'E475:')
1019  endif
1020endfunc
1021
1022func Test_terminal_response_to_control_sequence()
1023  CheckUnix
1024
1025  let buf = Run_shell_in_terminal({})
1026  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
1027
1028  call term_sendkeys(buf, "cat\<CR>")
1029  call WaitForAssert({-> assert_match('cat', term_getline(buf, 1))})
1030
1031  " Request the cursor position.
1032  call term_sendkeys(buf, "\x1b[6n\<CR>")
1033
1034  " Wait for output from tty to display, below an empty line.
1035  call WaitForAssert({-> assert_match('3;1R', term_getline(buf, 4))})
1036
1037  " End "cat" gently.
1038  call term_sendkeys(buf, "\<CR>\<C-D>")
1039
1040  call StopShellInTerminal(buf)
1041  exe buf . 'bwipe'
1042  unlet g:job
1043endfunc
1044
1045" Run Vim, start a terminal in that Vim with the kill argument,
1046" :qall works.
1047func Run_terminal_qall_kill(line1, line2)
1048  " 1. Open a terminal window and wait for the prompt to appear
1049  " 2. set kill using term_setkill()
1050  " 3. make Vim exit, it will kill the shell
1051  let after = [
1052	\ a:line1,
1053	\ 'let buf = bufnr("%")',
1054	\ 'while term_getline(buf, 1) =~ "^\\s*$"',
1055	\ '  sleep 10m',
1056	\ 'endwhile',
1057	\ a:line2,
1058	\ 'au VimLeavePre * call writefile(["done"], "Xdone")',
1059	\ 'qall',
1060	\ ]
1061  if !RunVim([], after, '')
1062    return
1063  endif
1064  call assert_equal("done", readfile("Xdone")[0])
1065  call delete("Xdone")
1066endfunc
1067
1068" Run Vim in a terminal, then start a terminal in that Vim with a kill
1069" argument, check that :qall works.
1070func Test_terminal_qall_kill_arg()
1071  call Run_terminal_qall_kill('term ++kill=kill', '')
1072endfunc
1073
1074" Run Vim, start a terminal in that Vim, set the kill argument with
1075" term_setkill(), check that :qall works.
1076func Test_terminal_qall_kill_func()
1077  call Run_terminal_qall_kill('term', 'eval buf->term_setkill("kill")')
1078endfunc
1079
1080" Run Vim, start a terminal in that Vim without the kill argument,
1081" check that :qall does not exit, :qall! does.
1082func Test_terminal_qall_exit()
1083  let after =<< trim [CODE]
1084    term
1085    let buf = bufnr("%")
1086    while term_getline(buf, 1) =~ "^\\s*$"
1087      sleep 10m
1088    endwhile
1089    set nomore
1090    au VimLeavePre * call writefile(["too early"], "Xdone")
1091    qall
1092    au! VimLeavePre * exe buf . "bwipe!" | call writefile(["done"], "Xdone")
1093    cquit
1094  [CODE]
1095
1096  if !RunVim([], after, '')
1097    return
1098  endif
1099  call assert_equal("done", readfile("Xdone")[0])
1100  call delete("Xdone")
1101endfunc
1102
1103" Run Vim in a terminal, then start a terminal in that Vim without a kill
1104" argument, check that :confirm qall works.
1105func Test_terminal_qall_prompt()
1106  CheckRunVimInTerminal
1107  let buf = RunVimInTerminal('', {})
1108
1109  " Open a terminal window and wait for the prompt to appear
1110  call term_sendkeys(buf, ":term\<CR>")
1111  call WaitForAssert({-> assert_match('\[running]', term_getline(buf, 10))})
1112  call WaitForAssert({-> assert_notmatch('^\s*$', term_getline(buf, 1))})
1113
1114  " make Vim exit, it will prompt to kill the shell
1115  call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>")
1116  call WaitForAssert({-> assert_match('ancel:', term_getline(buf, 20))})
1117  call term_sendkeys(buf, "y")
1118  call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
1119
1120  " close the terminal window where Vim was running
1121  quit
1122endfunc
1123
1124" Run Vim in a terminal, then start a terminal window with a shell and check
1125" that Vim exits if it is closed.
1126func Test_terminal_exit()
1127  CheckRunVimInTerminal
1128
1129  let lines =<< trim END
1130     let winid = win_getid()
1131     help
1132     term
1133     let termid = win_getid()
1134     call win_gotoid(winid)
1135     close
1136     call win_gotoid(termid)
1137  END
1138  call writefile(lines, 'XtermExit')
1139  let buf = RunVimInTerminal('-S XtermExit', #{rows: 10})
1140  let job = term_getjob(buf)
1141  call WaitForAssert({-> assert_equal("run", job_status(job))})
1142
1143  " quit the shell, it will make Vim exit
1144  call term_sendkeys(buf, "exit\<CR>")
1145  call WaitForAssert({-> assert_equal("dead", job_status(job))})
1146
1147  call delete('XtermExit')
1148endfunc
1149
1150func Test_terminal_open_autocmd()
1151  augroup repro
1152    au!
1153    au TerminalOpen * let s:called += 1
1154  augroup END
1155
1156  let s:called = 0
1157
1158  " Open a terminal window with :terminal
1159  terminal
1160  call assert_equal(1, s:called)
1161  bwipe!
1162
1163  " Open a terminal window with term_start()
1164  call term_start(&shell)
1165  call assert_equal(2, s:called)
1166  bwipe!
1167
1168  " Open a hidden terminal buffer with :terminal
1169  terminal ++hidden
1170  call assert_equal(3, s:called)
1171  for buf in term_list()
1172    exe buf . "bwipe!"
1173  endfor
1174
1175  " Open a hidden terminal buffer with term_start()
1176  let buf = term_start(&shell, {'hidden': 1})
1177  call assert_equal(4, s:called)
1178  exe buf . "bwipe!"
1179
1180  unlet s:called
1181  au! repro
1182endfunction
1183
1184func Check_dump01(off)
1185  call assert_equal('one two three four five', trim(getline(a:off + 1)))
1186  call assert_equal('~           Select Word', trim(getline(a:off + 7)))
1187  call assert_equal(':popup PopUp', trim(getline(a:off + 20)))
1188endfunc
1189
1190func Test_terminal_dumpwrite_composing()
1191  CheckRunVimInTerminal
1192  let save_enc = &encoding
1193  set encoding=utf-8
1194  call assert_equal(1, winnr('$'))
1195
1196  let text = " a\u0300 e\u0302 o\u0308"
1197  call writefile([text], 'Xcomposing')
1198  let buf = RunVimInTerminal('--cmd "set encoding=utf-8" Xcomposing', {})
1199  call WaitForAssert({-> assert_match(text, term_getline(buf, 1))})
1200  eval 'Xdump'->term_dumpwrite(buf)
1201  let dumpline = readfile('Xdump')[0]
1202  call assert_match('|à| |ê| |ö', dumpline)
1203
1204  call StopVimInTerminal(buf)
1205  call delete('Xcomposing')
1206  call delete('Xdump')
1207  let &encoding = save_enc
1208endfunc
1209
1210" Tests for failures in the term_dumpwrite() function
1211func Test_terminal_dumpwrite_errors()
1212  CheckRunVimInTerminal
1213  call assert_fails("call term_dumpwrite({}, 'Xtest.dump')", 'E728:')
1214  let buf = RunVimInTerminal('', {})
1215  call term_wait(buf)
1216  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump', '')", 'E715:')
1217  call assert_fails("call term_dumpwrite(buf, [])", 'E730:')
1218  call writefile([], 'Xtest.dump')
1219  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E953:')
1220  call delete('Xtest.dump')
1221  call assert_fails("call term_dumpwrite(buf, '')", 'E482:')
1222  call assert_fails("call term_dumpwrite(buf, test_null_string())", 'E482:')
1223  call StopVimInTerminal(buf)
1224  call term_wait(buf)
1225  call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E958:')
1226  call assert_fails('call term_sendkeys([], ":q\<CR>")', 'E745:')
1227  call assert_equal(0, term_sendkeys(buf, ":q\<CR>"))
1228endfunc
1229
1230" just testing basic functionality.
1231func Test_terminal_dumpload()
1232  let curbuf = winbufnr('')
1233  call assert_equal(1, winnr('$'))
1234  let buf = term_dumpload('dumps/Test_popup_command_01.dump')
1235  call assert_equal(2, winnr('$'))
1236  call assert_equal(20, line('$'))
1237  call Check_dump01(0)
1238
1239  " Load another dump in the same window
1240  let buf2 = 'dumps/Test_diff_01.dump'->term_dumpload({'bufnr': buf})
1241  call assert_equal(buf, buf2)
1242  call assert_notequal('one two three four five', trim(getline(1)))
1243
1244  " Load the first dump again in the same window
1245  let buf2 = term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': buf})
1246  call assert_equal(buf, buf2)
1247  call Check_dump01(0)
1248
1249  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': curbuf})", 'E475:')
1250  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': 9999})", 'E86:')
1251  new
1252  let closedbuf = winbufnr('')
1253  quit
1254  call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': closedbuf})", 'E475:')
1255  call assert_fails('call term_dumpload([])', 'E474:')
1256  call assert_fails('call term_dumpload("xabcy.dump")', 'E485:')
1257
1258  quit
1259endfunc
1260
1261func Test_terminal_dumpload_dump()
1262  CheckRunVimInTerminal
1263
1264  let lines =<< trim END
1265     call term_dumpload('dumps/Test_popupwin_22.dump', #{term_rows: 12})
1266  END
1267  call writefile(lines, 'XtermDumpload')
1268  let buf = RunVimInTerminal('-S XtermDumpload', #{rows: 15})
1269  call VerifyScreenDump(buf, 'Test_terminal_dumpload', {})
1270
1271  call StopVimInTerminal(buf)
1272  call delete('XtermDumpload')
1273endfunc
1274
1275func Test_terminal_dumpdiff()
1276  call assert_equal(1, winnr('$'))
1277  eval 'dumps/Test_popup_command_01.dump'->term_dumpdiff('dumps/Test_popup_command_02.dump')
1278  call assert_equal(2, winnr('$'))
1279  call assert_equal(62, line('$'))
1280  call Check_dump01(0)
1281  call Check_dump01(42)
1282  call assert_equal('           bbbbbbbbbbbbbbbbbb ', getline(26)[0:29])
1283  quit
1284
1285  call assert_fails('call term_dumpdiff("X1.dump", [])', 'E474:')
1286  call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:')
1287  call writefile([], 'X1.dump')
1288  call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:')
1289  call delete('X1.dump')
1290endfunc
1291
1292func Test_terminal_dumpdiff_swap()
1293  call assert_equal(1, winnr('$'))
1294  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_03.dump')
1295  call assert_equal(2, winnr('$'))
1296  call assert_equal(62, line('$'))
1297  call assert_match('Test_popup_command_01.dump', getline(21))
1298  call assert_match('Test_popup_command_03.dump', getline(42))
1299  call assert_match('Undo', getline(3))
1300  call assert_match('three four five', getline(45))
1301
1302  normal s
1303  call assert_match('Test_popup_command_03.dump', getline(21))
1304  call assert_match('Test_popup_command_01.dump', getline(42))
1305  call assert_match('three four five', getline(3))
1306  call assert_match('Undo', getline(45))
1307  quit
1308endfunc
1309
1310func Test_terminal_dumpdiff_options()
1311  set laststatus=0
1312  call assert_equal(1, winnr('$'))
1313  let height = winheight(0)
1314  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 1, 'term_cols': 33})
1315  call assert_equal(2, winnr('$'))
1316  call assert_equal(height, winheight(winnr()))
1317  call assert_equal(33, winwidth(winnr()))
1318  call assert_equal('dump diff dumps/Test_popup_command_01.dump', bufname('%'))
1319  quit
1320
1321  call assert_equal(1, winnr('$'))
1322  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 0, 'term_rows': 13, 'term_name': 'something else'})
1323  call assert_equal(2, winnr('$'))
1324  call assert_equal(&columns, winwidth(0))
1325  call assert_equal(13, winheight(0))
1326  call assert_equal('something else', bufname('%'))
1327  quit
1328
1329  call assert_equal(1, winnr('$'))
1330  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1})
1331  call assert_equal(1, winnr('$'))
1332  call assert_fails("call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'bufnr': -1})", 'E475:')
1333  bwipe
1334
1335  set laststatus&
1336endfunc
1337
1338func Api_drop_common(options)
1339  call assert_equal(1, winnr('$'))
1340
1341  " Use the title termcap entries to output the escape sequence.
1342  call writefile([
1343	\ 'set title',
1344	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1345	\ 'let &titlestring = ''["drop","Xtextfile"' . a:options . ']''',
1346	\ 'redraw',
1347	\ "set t_ts=",
1348	\ ], 'Xscript')
1349  let buf = RunVimInTerminal('-S Xscript', {})
1350  call WaitFor({-> bufnr('Xtextfile') > 0})
1351  call assert_equal('Xtextfile', expand('%:t'))
1352  call assert_true(winnr('$') >= 3)
1353  return buf
1354endfunc
1355
1356func Test_terminal_api_drop_newwin()
1357  CheckRunVimInTerminal
1358  let buf = Api_drop_common('')
1359  call assert_equal(0, &bin)
1360  call assert_equal('', &fenc)
1361
1362  call StopVimInTerminal(buf)
1363  call delete('Xscript')
1364  bwipe Xtextfile
1365endfunc
1366
1367func Test_terminal_api_drop_newwin_bin()
1368  CheckRunVimInTerminal
1369  let buf = Api_drop_common(',{"bin":1}')
1370  call assert_equal(1, &bin)
1371
1372  call StopVimInTerminal(buf)
1373  call delete('Xscript')
1374  bwipe Xtextfile
1375endfunc
1376
1377func Test_terminal_api_drop_newwin_binary()
1378  CheckRunVimInTerminal
1379  let buf = Api_drop_common(',{"binary":1}')
1380  call assert_equal(1, &bin)
1381
1382  call StopVimInTerminal(buf)
1383  call delete('Xscript')
1384  bwipe Xtextfile
1385endfunc
1386
1387func Test_terminal_api_drop_newwin_nobin()
1388  CheckRunVimInTerminal
1389  set binary
1390  let buf = Api_drop_common(',{"nobin":1}')
1391  call assert_equal(0, &bin)
1392
1393  call StopVimInTerminal(buf)
1394  call delete('Xscript')
1395  bwipe Xtextfile
1396  set nobinary
1397endfunc
1398
1399func Test_terminal_api_drop_newwin_nobinary()
1400  CheckRunVimInTerminal
1401  set binary
1402  let buf = Api_drop_common(',{"nobinary":1}')
1403  call assert_equal(0, &bin)
1404
1405  call StopVimInTerminal(buf)
1406  call delete('Xscript')
1407  bwipe Xtextfile
1408  set nobinary
1409endfunc
1410
1411func Test_terminal_api_drop_newwin_ff()
1412  CheckRunVimInTerminal
1413  let buf = Api_drop_common(',{"ff":"dos"}')
1414  call assert_equal("dos", &ff)
1415
1416  call StopVimInTerminal(buf)
1417  call delete('Xscript')
1418  bwipe Xtextfile
1419endfunc
1420
1421func Test_terminal_api_drop_newwin_fileformat()
1422  CheckRunVimInTerminal
1423  let buf = Api_drop_common(',{"fileformat":"dos"}')
1424  call assert_equal("dos", &ff)
1425
1426  call StopVimInTerminal(buf)
1427  call delete('Xscript')
1428  bwipe Xtextfile
1429endfunc
1430
1431func Test_terminal_api_drop_newwin_enc()
1432  CheckRunVimInTerminal
1433  let buf = Api_drop_common(',{"enc":"utf-16"}')
1434  call assert_equal("utf-16", &fenc)
1435
1436  call StopVimInTerminal(buf)
1437  call delete('Xscript')
1438  bwipe Xtextfile
1439endfunc
1440
1441func Test_terminal_api_drop_newwin_encoding()
1442  CheckRunVimInTerminal
1443  let buf = Api_drop_common(',{"encoding":"utf-16"}')
1444  call assert_equal("utf-16", &fenc)
1445
1446  call StopVimInTerminal(buf)
1447  call delete('Xscript')
1448  bwipe Xtextfile
1449endfunc
1450
1451func Test_terminal_api_drop_oldwin()
1452  CheckRunVimInTerminal
1453  let firstwinid = win_getid()
1454  split Xtextfile
1455  let textfile_winid = win_getid()
1456  call assert_equal(2, winnr('$'))
1457  call win_gotoid(firstwinid)
1458
1459  " Use the title termcap entries to output the escape sequence.
1460  call writefile([
1461	\ 'set title',
1462	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1463	\ 'let &titlestring = ''["drop","Xtextfile"]''',
1464	\ 'redraw',
1465	\ "set t_ts=",
1466	\ ], 'Xscript')
1467  let buf = RunVimInTerminal('-S Xscript', {'rows': 10})
1468  call WaitForAssert({-> assert_equal('Xtextfile', expand('%:t'))})
1469  call assert_equal(textfile_winid, win_getid())
1470
1471  call StopVimInTerminal(buf)
1472  call delete('Xscript')
1473  bwipe Xtextfile
1474endfunc
1475
1476func Tapi_TryThis(bufnum, arg)
1477  let g:called_bufnum = a:bufnum
1478  let g:called_arg = a:arg
1479endfunc
1480
1481func WriteApiCall(funcname)
1482  " Use the title termcap entries to output the escape sequence.
1483  call writefile([
1484	\ 'set title',
1485	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1486	\ 'let &titlestring = ''["call","' . a:funcname . '",["hello",123]]''',
1487	\ 'redraw',
1488	\ "set t_ts=",
1489	\ ], 'Xscript')
1490endfunc
1491
1492func Test_terminal_api_call()
1493  CheckRunVimInTerminal
1494
1495  unlet! g:called_bufnum
1496  unlet! g:called_arg
1497
1498  call WriteApiCall('Tapi_TryThis')
1499
1500  " Default
1501  let buf = RunVimInTerminal('-S Xscript', {})
1502  call WaitFor({-> exists('g:called_bufnum')})
1503  call assert_equal(buf, g:called_bufnum)
1504  call assert_equal(['hello', 123], g:called_arg)
1505  call StopVimInTerminal(buf)
1506
1507  unlet! g:called_bufnum
1508  unlet! g:called_arg
1509
1510  " Enable explicitly
1511  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'Tapi_Try'})
1512  call WaitFor({-> exists('g:called_bufnum')})
1513  call assert_equal(buf, g:called_bufnum)
1514  call assert_equal(['hello', 123], g:called_arg)
1515  call StopVimInTerminal(buf)
1516
1517  unlet! g:called_bufnum
1518  unlet! g:called_arg
1519
1520  func! ApiCall_TryThis(bufnum, arg)
1521    let g:called_bufnum2 = a:bufnum
1522    let g:called_arg2 = a:arg
1523  endfunc
1524
1525  call WriteApiCall('ApiCall_TryThis')
1526
1527  " Use prefix match
1528  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'ApiCall_'})
1529  call WaitFor({-> exists('g:called_bufnum2')})
1530  call assert_equal(buf, g:called_bufnum2)
1531  call assert_equal(['hello', 123], g:called_arg2)
1532  call StopVimInTerminal(buf)
1533
1534  call assert_fails("call term_start('ls', {'term_api' : []})", 'E475:')
1535
1536  unlet! g:called_bufnum2
1537  unlet! g:called_arg2
1538
1539  call delete('Xscript')
1540  delfunction! ApiCall_TryThis
1541  unlet! g:called_bufnum2
1542  unlet! g:called_arg2
1543endfunc
1544
1545func Test_terminal_api_call_fails()
1546  CheckRunVimInTerminal
1547
1548  func! TryThis(bufnum, arg)
1549    let g:called_bufnum3 = a:bufnum
1550    let g:called_arg3 = a:arg
1551  endfunc
1552
1553  call WriteApiCall('TryThis')
1554
1555  unlet! g:called_bufnum3
1556  unlet! g:called_arg3
1557
1558  " Not permitted
1559  call ch_logfile('Xlog', 'w')
1560  let buf = RunVimInTerminal('-S Xscript', {'term_api': ''})
1561  call WaitForAssert({-> assert_match('Unpermitted function: TryThis', string(readfile('Xlog')))})
1562  call assert_false(exists('g:called_bufnum3'))
1563  call assert_false(exists('g:called_arg3'))
1564  call StopVimInTerminal(buf)
1565
1566  " No match
1567  call ch_logfile('Xlog', 'w')
1568  let buf = RunVimInTerminal('-S Xscript', {'term_api': 'TryThat'})
1569  call WaitFor({-> string(readfile('Xlog')) =~ 'Unpermitted function: TryThis'})
1570  call assert_false(exists('g:called_bufnum3'))
1571  call assert_false(exists('g:called_arg3'))
1572  call StopVimInTerminal(buf)
1573
1574  call delete('Xscript')
1575  call ch_logfile('')
1576  call delete('Xlog')
1577  delfunction! TryThis
1578  unlet! g:called_bufnum3
1579  unlet! g:called_arg3
1580endfunc
1581
1582let s:caught_e937 = 0
1583
1584func Tapi_Delete(bufnum, arg)
1585  try
1586    execute 'bdelete!' a:bufnum
1587  catch /E937:/
1588    let s:caught_e937 = 1
1589  endtry
1590endfunc
1591
1592func Test_terminal_api_call_fail_delete()
1593  CheckRunVimInTerminal
1594
1595  call WriteApiCall('Tapi_Delete')
1596  let buf = RunVimInTerminal('-S Xscript', {})
1597  call WaitForAssert({-> assert_equal(1, s:caught_e937)})
1598
1599  call StopVimInTerminal(buf)
1600  call delete('Xscript')
1601  call ch_logfile('', '')
1602endfunc
1603
1604func Test_terminal_ansicolors_default()
1605  CheckFunction term_getansicolors
1606
1607  let colors = [
1608	\ '#000000', '#e00000',
1609	\ '#00e000', '#e0e000',
1610	\ '#0000e0', '#e000e0',
1611	\ '#00e0e0', '#e0e0e0',
1612	\ '#808080', '#ff4040',
1613	\ '#40ff40', '#ffff40',
1614	\ '#4040ff', '#ff40ff',
1615	\ '#40ffff', '#ffffff',
1616	\]
1617
1618  let buf = Run_shell_in_terminal({})
1619  call assert_equal(colors, term_getansicolors(buf))
1620  call StopShellInTerminal(buf)
1621  call TermWait(buf)
1622
1623  exe buf . 'bwipe'
1624endfunc
1625
1626let s:test_colors = [
1627	\ '#616e64', '#0d0a79',
1628	\ '#6d610d', '#0a7373',
1629	\ '#690d0a', '#6d696e',
1630	\ '#0d0a6f', '#616e0d',
1631	\ '#0a6479', '#6d0d0a',
1632	\ '#617373', '#0d0a69',
1633	\ '#6d690d', '#0a6e6f',
1634	\ '#610d0a', '#6e6479',
1635	\]
1636
1637func Test_terminal_ansicolors_global()
1638  CheckFeature termguicolors
1639  CheckFunction term_getansicolors
1640
1641  let g:terminal_ansi_colors = reverse(copy(s:test_colors))
1642  let buf = Run_shell_in_terminal({})
1643  call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
1644  call StopShellInTerminal(buf)
1645  call TermWait(buf)
1646
1647  exe buf . 'bwipe'
1648  unlet g:terminal_ansi_colors
1649endfunc
1650
1651func Test_terminal_ansicolors_func()
1652  CheckFeature termguicolors
1653  CheckFunction term_getansicolors
1654
1655  let g:terminal_ansi_colors = reverse(copy(s:test_colors))
1656  let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors})
1657  call assert_equal(s:test_colors, term_getansicolors(buf))
1658
1659  call term_setansicolors(buf, g:terminal_ansi_colors)
1660  call assert_equal(g:terminal_ansi_colors, buf->term_getansicolors())
1661
1662  let colors = [
1663	\ 'ivory', 'AliceBlue',
1664	\ 'grey67', 'dark goldenrod',
1665	\ 'SteelBlue3', 'PaleVioletRed4',
1666	\ 'MediumPurple2', 'yellow2',
1667	\ 'RosyBrown3', 'OrangeRed2',
1668	\ 'white smoke', 'navy blue',
1669	\ 'grey47', 'gray97',
1670	\ 'MistyRose2', 'DodgerBlue4',
1671	\]
1672  eval buf->term_setansicolors(colors)
1673
1674  let colors[4] = 'Invalid'
1675  call assert_fails('call term_setansicolors(buf, colors)', 'E474:')
1676
1677  call StopShellInTerminal(buf)
1678  call TermWait(buf)
1679  exe buf . 'bwipe'
1680endfunc
1681
1682func Test_terminal_all_ansi_colors()
1683  CheckRunVimInTerminal
1684
1685  " Use all the ANSI colors.
1686  call writefile([
1687	\ 'call setline(1, "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPP XXYYZZ")',
1688	\ 'hi Tblack ctermfg=0 ctermbg=8',
1689	\ 'hi Tdarkred ctermfg=1 ctermbg=9',
1690	\ 'hi Tdarkgreen ctermfg=2 ctermbg=10',
1691	\ 'hi Tbrown ctermfg=3 ctermbg=11',
1692	\ 'hi Tdarkblue ctermfg=4 ctermbg=12',
1693	\ 'hi Tdarkmagenta ctermfg=5 ctermbg=13',
1694	\ 'hi Tdarkcyan ctermfg=6 ctermbg=14',
1695	\ 'hi Tlightgrey ctermfg=7 ctermbg=15',
1696	\ 'hi Tdarkgrey ctermfg=8 ctermbg=0',
1697	\ 'hi Tred ctermfg=9 ctermbg=1',
1698	\ 'hi Tgreen ctermfg=10 ctermbg=2',
1699	\ 'hi Tyellow ctermfg=11 ctermbg=3',
1700	\ 'hi Tblue ctermfg=12 ctermbg=4',
1701	\ 'hi Tmagenta ctermfg=13 ctermbg=5',
1702	\ 'hi Tcyan ctermfg=14 ctermbg=6',
1703	\ 'hi Twhite ctermfg=15 ctermbg=7',
1704	\ 'hi TdarkredBold ctermfg=1 cterm=bold',
1705	\ 'hi TgreenBold ctermfg=10 cterm=bold',
1706	\ 'hi TmagentaBold ctermfg=13 cterm=bold ctermbg=5',
1707	\ '',
1708	\ 'call  matchadd("Tblack", "A")',
1709	\ 'call  matchadd("Tdarkred", "B")',
1710	\ 'call  matchadd("Tdarkgreen", "C")',
1711	\ 'call  matchadd("Tbrown", "D")',
1712	\ 'call  matchadd("Tdarkblue", "E")',
1713	\ 'call  matchadd("Tdarkmagenta", "F")',
1714	\ 'call  matchadd("Tdarkcyan", "G")',
1715	\ 'call  matchadd("Tlightgrey", "H")',
1716	\ 'call  matchadd("Tdarkgrey", "I")',
1717	\ 'call  matchadd("Tred", "J")',
1718	\ 'call  matchadd("Tgreen", "K")',
1719	\ 'call  matchadd("Tyellow", "L")',
1720	\ 'call  matchadd("Tblue", "M")',
1721	\ 'call  matchadd("Tmagenta", "N")',
1722	\ 'call  matchadd("Tcyan", "O")',
1723	\ 'call  matchadd("Twhite", "P")',
1724	\ 'call  matchadd("TdarkredBold", "X")',
1725	\ 'call  matchadd("TgreenBold", "Y")',
1726	\ 'call  matchadd("TmagentaBold", "Z")',
1727	\ 'redraw',
1728	\ ], 'Xcolorscript')
1729  let buf = RunVimInTerminal('-S Xcolorscript', {'rows': 10})
1730  call VerifyScreenDump(buf, 'Test_terminal_all_ansi_colors', {})
1731
1732  call term_sendkeys(buf, ":q\<CR>")
1733  call StopVimInTerminal(buf)
1734  call delete('Xcolorscript')
1735endfunc
1736
1737func Test_terminal_termwinsize_option_fixed()
1738  CheckRunVimInTerminal
1739  set termwinsize=6x40
1740  let text = []
1741  for n in range(10)
1742    call add(text, repeat(n, 50))
1743  endfor
1744  call writefile(text, 'Xwinsize')
1745  let buf = RunVimInTerminal('Xwinsize', {})
1746  let win = bufwinid(buf)
1747  call assert_equal([6, 40], term_getsize(buf))
1748  call assert_equal(6, winheight(win))
1749  call assert_equal(40, winwidth(win))
1750
1751  " resizing the window doesn't resize the terminal.
1752  resize 10
1753  vertical resize 60
1754  call assert_equal([6, 40], term_getsize(buf))
1755  call assert_equal(10, winheight(win))
1756  call assert_equal(60, winwidth(win))
1757
1758  call StopVimInTerminal(buf)
1759  call delete('Xwinsize')
1760
1761  call assert_fails('set termwinsize=40', 'E474')
1762  call assert_fails('set termwinsize=10+40', 'E474')
1763  call assert_fails('set termwinsize=abc', 'E474')
1764
1765  set termwinsize=
1766endfunc
1767
1768func Test_terminal_termwinsize_option_zero()
1769  set termwinsize=0x0
1770  let buf = Run_shell_in_terminal({})
1771  let win = bufwinid(buf)
1772  call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
1773  call StopShellInTerminal(buf)
1774  call TermWait(buf)
1775  exe buf . 'bwipe'
1776
1777  set termwinsize=7x0
1778  let buf = Run_shell_in_terminal({})
1779  let win = bufwinid(buf)
1780  call assert_equal([7, winwidth(win)], term_getsize(buf))
1781  call StopShellInTerminal(buf)
1782  call TermWait(buf)
1783  exe buf . 'bwipe'
1784
1785  set termwinsize=0x33
1786  let buf = Run_shell_in_terminal({})
1787  let win = bufwinid(buf)
1788  call assert_equal([winheight(win), 33], term_getsize(buf))
1789  call StopShellInTerminal(buf)
1790  call TermWait(buf)
1791  exe buf . 'bwipe'
1792
1793  set termwinsize=
1794endfunc
1795
1796func Test_terminal_termwinsize_minimum()
1797  set termwinsize=10*50
1798  vsplit
1799  let buf = Run_shell_in_terminal({})
1800  let win = bufwinid(buf)
1801  call assert_inrange(10, 1000, winheight(win))
1802  call assert_inrange(50, 1000, winwidth(win))
1803  call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
1804
1805  resize 15
1806  vertical resize 60
1807  redraw
1808  call assert_equal([15, 60], term_getsize(buf))
1809  call assert_equal(15, winheight(win))
1810  call assert_equal(60, winwidth(win))
1811
1812  resize 7
1813  vertical resize 30
1814  redraw
1815  call assert_equal([10, 50], term_getsize(buf))
1816  call assert_equal(7, winheight(win))
1817  call assert_equal(30, winwidth(win))
1818
1819  call StopShellInTerminal(buf)
1820  call TermWait(buf)
1821  exe buf . 'bwipe'
1822
1823  set termwinsize=0*0
1824  let buf = Run_shell_in_terminal({})
1825  let win = bufwinid(buf)
1826  call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
1827  call StopShellInTerminal(buf)
1828  call TermWait(buf)
1829  exe buf . 'bwipe'
1830
1831  set termwinsize=
1832endfunc
1833
1834func Test_terminal_termwinkey()
1835  " make three tabpages, terminal in the middle
1836  0tabnew
1837  tabnext
1838  tabnew
1839  tabprev
1840  call assert_equal(1, winnr('$'))
1841  call assert_equal(2, tabpagenr())
1842  let thiswin = win_getid()
1843
1844  let buf = Run_shell_in_terminal({})
1845  let termwin = bufwinid(buf)
1846  set termwinkey=<C-L>
1847  call feedkeys("\<C-L>w", 'tx')
1848  call assert_equal(thiswin, win_getid())
1849  call feedkeys("\<C-W>w", 'tx')
1850  call assert_equal(termwin, win_getid())
1851
1852  if has('langmap')
1853    set langmap=xjyk
1854    call feedkeys("\<C-L>x", 'tx')
1855    call assert_equal(thiswin, win_getid())
1856    call feedkeys("\<C-W>y", 'tx')
1857    call assert_equal(termwin, win_getid())
1858    set langmap=
1859  endif
1860
1861  call feedkeys("\<C-L>gt", "xt")
1862  call assert_equal(3, tabpagenr())
1863  tabprev
1864  call assert_equal(2, tabpagenr())
1865  call assert_equal(termwin, win_getid())
1866
1867  call feedkeys("\<C-L>gT", "xt")
1868  call assert_equal(1, tabpagenr())
1869  tabnext
1870  call assert_equal(2, tabpagenr())
1871  call assert_equal(termwin, win_getid())
1872
1873  let job = term_getjob(buf)
1874  call feedkeys("\<C-L>\<C-C>", 'tx')
1875  call WaitForAssert({-> assert_equal("dead", job_status(job))})
1876
1877  set termwinkey&
1878  tabnext
1879  tabclose
1880  tabprev
1881  tabclose
1882endfunc
1883
1884func Test_terminal_out_err()
1885  CheckUnix
1886
1887  call writefile([
1888	\ '#!/bin/sh',
1889	\ 'echo "this is standard error" >&2',
1890	\ 'echo "this is standard out" >&1',
1891	\ ], 'Xechoerrout.sh')
1892  call setfperm('Xechoerrout.sh', 'rwxrwx---')
1893
1894  let outfile = 'Xtermstdout'
1895  let buf = term_start(['./Xechoerrout.sh'], {'out_io': 'file', 'out_name': outfile})
1896
1897  call WaitFor({-> !empty(readfile(outfile)) && !empty(term_getline(buf, 1))})
1898  call assert_equal(['this is standard out'], readfile(outfile))
1899  call assert_equal('this is standard error', term_getline(buf, 1))
1900
1901  call WaitForAssert({-> assert_equal('dead', job_status(term_getjob(buf)))})
1902  exe buf . 'bwipe'
1903  call delete('Xechoerrout.sh')
1904  call delete(outfile)
1905endfunc
1906
1907func Test_termwinscroll()
1908  CheckUnix
1909
1910  " Let the terminal output more than 'termwinscroll' lines, some at the start
1911  " will be dropped.
1912  exe 'set termwinscroll=' . &lines
1913  let buf = term_start('/bin/sh')
1914  for i in range(1, &lines)
1915    call feedkeys("echo " . i . "\<CR>", 'xt')
1916    call WaitForAssert({-> assert_match(string(i), term_getline(buf, term_getcursor(buf)[0] - 1))})
1917  endfor
1918  " Go to Terminal-Normal mode to update the buffer.
1919  call feedkeys("\<C-W>N", 'xt')
1920  call assert_inrange(&lines, &lines * 110 / 100 + winheight(0), line('$'))
1921
1922  " Every "echo nr" must only appear once
1923  let lines = getline(1, line('$'))
1924  for i in range(&lines - len(lines) / 2 + 2, &lines)
1925    let filtered = filter(copy(lines), {idx, val -> val =~ 'echo ' . i . '\>'})
1926    call assert_equal(1, len(filtered), 'for "echo ' . i . '"')
1927  endfor
1928
1929  exe buf . 'bwipe!'
1930endfunc
1931
1932" Resizing the terminal window caused an ml_get error.
1933" TODO: This does not reproduce the original problem.
1934func Test_terminal_resize()
1935  set statusline=x
1936  terminal
1937  call assert_equal(2, winnr('$'))
1938
1939  " Fill the terminal with text.
1940  if has('win32')
1941    call feedkeys("dir\<CR>", 'xt')
1942  else
1943    call feedkeys("ls\<CR>", 'xt')
1944  endif
1945  " Go to Terminal-Normal mode for a moment.
1946  call feedkeys("\<C-W>N", 'xt')
1947  " Open a new window
1948  call feedkeys("i\<C-W>n", 'xt')
1949  call assert_equal(3, winnr('$'))
1950  redraw
1951
1952  close
1953  call assert_equal(2, winnr('$'))
1954  call feedkeys("exit\<CR>", 'xt')
1955  set statusline&
1956endfunc
1957
1958" must be nearly the last, we can't go back from GUI to terminal
1959func Test_zz1_terminal_in_gui()
1960  CheckCanRunGui
1961
1962  " Ignore the "failed to create input context" error.
1963  call test_ignore_error('E285:')
1964
1965  gui -f
1966
1967  call assert_equal(1, winnr('$'))
1968  let buf = Run_shell_in_terminal({'term_finish': 'close'})
1969  call StopShellInTerminal(buf)
1970  call TermWait(buf)
1971
1972  " closing window wipes out the terminal buffer a with finished job
1973  call WaitForAssert({-> assert_equal(1, winnr('$'))})
1974  call assert_equal("", bufname(buf))
1975
1976  unlet g:job
1977endfunc
1978
1979func Test_zz2_terminal_guioptions_bang()
1980  CheckGui
1981  set guioptions+=!
1982
1983  let filename = 'Xtestscript'
1984  if has('win32')
1985    let filename .= '.bat'
1986    let prefix = ''
1987    let contents = ['@echo off', 'exit %1']
1988  else
1989    let filename .= '.sh'
1990    let prefix = './'
1991    let contents = ['#!/bin/sh', 'exit $1']
1992  endif
1993  call writefile(contents, filename)
1994  call setfperm(filename, 'rwxrwx---')
1995
1996  " Check if v:shell_error is equal to the exit status.
1997  let exitval = 0
1998  execute printf(':!%s%s %d', prefix, filename, exitval)
1999  call assert_equal(exitval, v:shell_error)
2000
2001  let exitval = 9
2002  execute printf(':!%s%s %d', prefix, filename, exitval)
2003  call assert_equal(exitval, v:shell_error)
2004
2005  set guioptions&
2006  call delete(filename)
2007endfunc
2008
2009func Test_terminal_hidden()
2010  CheckUnix
2011
2012  term ++hidden cat
2013  let bnr = bufnr('$')
2014  call assert_equal('terminal', getbufvar(bnr, '&buftype'))
2015  exe 'sbuf ' . bnr
2016  call assert_equal('terminal', &buftype)
2017  call term_sendkeys(bnr, "asdf\<CR>")
2018  call WaitForAssert({-> assert_match('asdf', term_getline(bnr, 2))})
2019  call term_sendkeys(bnr, "\<C-D>")
2020  call WaitForAssert({-> assert_equal('finished', bnr->term_getstatus())})
2021  bwipe!
2022endfunc
2023
2024func Test_terminal_switch_mode()
2025  term
2026  let bnr = bufnr('$')
2027  call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))})
2028  call feedkeys("\<C-W>N", 'xt')
2029  call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))})
2030  call feedkeys("A", 'xt')
2031  call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))})
2032  call feedkeys("\<C-W>N", 'xt')
2033  call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))})
2034  call feedkeys("I", 'xt')
2035  call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))})
2036  call feedkeys("\<C-W>Nv", 'xt')
2037  call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))})
2038  call feedkeys("I", 'xt')
2039  call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))})
2040  call feedkeys("\<C-W>Nv", 'xt')
2041  call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))})
2042  call feedkeys("A", 'xt')
2043  call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))})
2044  bwipe!
2045endfunc
2046
2047func Test_terminal_normal_mode()
2048  CheckRunVimInTerminal
2049
2050  " Run Vim in a terminal and open a terminal window to run Vim in.
2051  let lines =<< trim END
2052    call setline(1, range(11111, 11122))
2053    3
2054  END
2055  call writefile(lines, 'XtermNormal')
2056  let buf = RunVimInTerminal('-S XtermNormal', {'rows': 8})
2057  call TermWait(buf)
2058
2059  call term_sendkeys(buf, "\<C-W>N")
2060  call term_sendkeys(buf, ":set number cursorline culopt=both\r")
2061  call VerifyScreenDump(buf, 'Test_terminal_normal_1', {})
2062
2063  call term_sendkeys(buf, ":set culopt=number\r")
2064  call VerifyScreenDump(buf, 'Test_terminal_normal_2', {})
2065
2066  call term_sendkeys(buf, ":set culopt=line\r")
2067  call VerifyScreenDump(buf, 'Test_terminal_normal_3', {})
2068
2069  call term_sendkeys(buf, "a:q!\<CR>:q\<CR>:q\<CR>")
2070  call StopVimInTerminal(buf)
2071  call delete('XtermNormal')
2072endfunc
2073
2074func Test_terminal_hidden_and_close()
2075  CheckUnix
2076
2077  call assert_equal(1, winnr('$'))
2078  term ++hidden ++close ls
2079  let bnr = bufnr('$')
2080  call assert_equal('terminal', getbufvar(bnr, '&buftype'))
2081  call WaitForAssert({-> assert_false(bufexists(bnr))})
2082  call assert_equal(1, winnr('$'))
2083endfunc
2084
2085func Test_terminal_does_not_truncate_last_newlines()
2086  " This test does not pass through ConPTY.
2087  if has('conpty')
2088    return
2089  endif
2090  let contents = [
2091  \   [ 'One', '', 'X' ],
2092  \   [ 'Two', '', '' ],
2093  \   [ 'Three' ] + repeat([''], 30)
2094  \ ]
2095
2096  for c in contents
2097    call writefile(c, 'Xfile')
2098    if has('win32')
2099      term cmd /c type Xfile
2100    else
2101      term cat Xfile
2102    endif
2103    let bnr = bufnr('$')
2104    call assert_equal('terminal', getbufvar(bnr, '&buftype'))
2105    call WaitForAssert({-> assert_equal('finished', term_getstatus(bnr))})
2106    sleep 100m
2107    call assert_equal(c, getline(1, line('$')))
2108    quit
2109  endfor
2110
2111  call delete('Xfile')
2112endfunc
2113
2114func Test_terminal_no_job()
2115  if has('win32')
2116    let cmd = 'cmd /c ""'
2117  else
2118    CheckExecutable false
2119    let cmd = 'false'
2120  endif
2121  let term = term_start(cmd, {'term_finish': 'close'})
2122  call WaitForAssert({-> assert_equal(v:null, term_getjob(term)) })
2123endfunc
2124
2125func Test_term_getcursor()
2126  CheckUnix
2127
2128  let buf = Run_shell_in_terminal({})
2129
2130  " Wait for the shell to display a prompt.
2131  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
2132
2133  " Hide the cursor.
2134  call term_sendkeys(buf, "echo -e '\\033[?25l'\r")
2135  call WaitForAssert({-> assert_equal(0, term_getcursor(buf)[2].visible)})
2136
2137  " Show the cursor.
2138  call term_sendkeys(buf, "echo -e '\\033[?25h'\r")
2139  call WaitForAssert({-> assert_equal(1, buf->term_getcursor()[2].visible)})
2140
2141  " Change color of cursor.
2142  call WaitForAssert({-> assert_equal('', term_getcursor(buf)[2].color)})
2143  call term_sendkeys(buf, "echo -e '\\033]12;blue\\007'\r")
2144  call WaitForAssert({-> assert_equal('blue', term_getcursor(buf)[2].color)})
2145  call term_sendkeys(buf, "echo -e '\\033]12;green\\007'\r")
2146  call WaitForAssert({-> assert_equal('green', term_getcursor(buf)[2].color)})
2147
2148  " Make cursor a blinking block.
2149  call term_sendkeys(buf, "echo -e '\\033[1 q'\r")
2150  call WaitForAssert({-> assert_equal([1, 1],
2151  \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])})
2152
2153  " Make cursor a steady block.
2154  call term_sendkeys(buf, "echo -e '\\033[2 q'\r")
2155  call WaitForAssert({-> assert_equal([0, 1],
2156  \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])})
2157
2158  " Make cursor a blinking underline.
2159  call term_sendkeys(buf, "echo -e '\\033[3 q'\r")
2160  call WaitForAssert({-> assert_equal([1, 2],
2161  \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])})
2162
2163  " Make cursor a steady underline.
2164  call term_sendkeys(buf, "echo -e '\\033[4 q'\r")
2165  call WaitForAssert({-> assert_equal([0, 2],
2166  \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])})
2167
2168  " Make cursor a blinking vertical bar.
2169  call term_sendkeys(buf, "echo -e '\\033[5 q'\r")
2170  call WaitForAssert({-> assert_equal([1, 3],
2171  \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])})
2172
2173  " Make cursor a steady vertical bar.
2174  call term_sendkeys(buf, "echo -e '\\033[6 q'\r")
2175  call WaitForAssert({-> assert_equal([0, 3],
2176  \ [term_getcursor(buf)[2].blink, term_getcursor(buf)[2].shape])})
2177
2178  call StopShellInTerminal(buf)
2179endfunc
2180
2181func Test_term_gettitle()
2182  " term_gettitle() returns an empty string for a non-terminal buffer
2183  " and for a non-existing buffer.
2184  call assert_equal('', bufnr('%')->term_gettitle())
2185  call assert_equal('', term_gettitle(bufnr('$') + 1))
2186
2187  if !has('title') || &title == 0 || empty(&t_ts)
2188    throw "Skipped: can't get/set title"
2189  endif
2190
2191  let term = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'])
2192  if has('autoservername')
2193    call WaitForAssert({-> assert_match('^\[No Name\] - VIM\d\+$', term_gettitle(term)) })
2194    call term_sendkeys(term, ":e Xfoo\r")
2195    call WaitForAssert({-> assert_match('^Xfoo (.*[/\\]testdir) - VIM\d\+$', term_gettitle(term)) })
2196  else
2197    call WaitForAssert({-> assert_equal('[No Name] - VIM', term_gettitle(term)) })
2198    call term_sendkeys(term, ":e Xfoo\r")
2199    call WaitForAssert({-> assert_match('^Xfoo (.*[/\\]testdir) - VIM$', term_gettitle(term)) })
2200  endif
2201
2202  call term_sendkeys(term, ":set titlestring=foo\r")
2203  call WaitForAssert({-> assert_equal('foo', term_gettitle(term)) })
2204
2205  exe term . 'bwipe!'
2206endfunc
2207
2208func Test_term_gettty()
2209  let buf = Run_shell_in_terminal({})
2210  let gettty = term_gettty(buf)
2211
2212  if has('unix') && executable('tty')
2213    " Find tty using the tty shell command.
2214    call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
2215    call term_sendkeys(buf, "tty\r")
2216    call WaitForAssert({-> assert_notequal('', term_getline(buf, 3))})
2217    let tty = term_getline(buf, 2)
2218    call assert_equal(tty, gettty)
2219  endif
2220
2221  let gettty0 = term_gettty(buf, 0)
2222  let gettty1 = term_gettty(buf, 1)
2223
2224  call assert_equal(gettty, gettty0)
2225  call assert_equal(job_info(g:job).tty_out, gettty0)
2226  call assert_equal(job_info(g:job).tty_in,  gettty1)
2227
2228  if has('unix')
2229    " For unix, term_gettty(..., 0) and term_gettty(..., 1)
2230    " are identical according to :help term_gettty()
2231    call assert_equal(gettty0, gettty1)
2232    call assert_match('^/dev/', gettty)
2233  else
2234    " ConPTY works on anonymous pipe.
2235    if !has('conpty')
2236      call assert_match('^\\\\.\\pipe\\', gettty0)
2237      call assert_match('^\\\\.\\pipe\\', gettty1)
2238    endif
2239  endif
2240
2241  call assert_fails('call term_gettty(buf, 2)', 'E475:')
2242  call assert_fails('call term_gettty(buf, -1)', 'E475:')
2243
2244  call assert_equal('', term_gettty(buf + 1))
2245
2246  call StopShellInTerminal(buf)
2247  call TermWait(buf)
2248  exe buf . 'bwipe'
2249endfunc
2250
2251" When drawing the statusline the cursor position may not have been updated
2252" yet.
2253" 1. create a terminal, make it show 2 lines
2254" 2. 0.5 sec later: leave terminal window, execute "i"
2255" 3. 0.5 sec later: clear terminal window, now it's 1 line
2256" 4. 0.5 sec later: redraw, including statusline (used to trigger bug)
2257" 4. 0.5 sec later: should be done, clean up
2258func Test_terminal_statusline()
2259  CheckUnix
2260
2261  set statusline=x
2262  terminal
2263  let tbuf = bufnr('')
2264  call term_sendkeys(tbuf, "clear; echo a; echo b; sleep 1; clear\n")
2265  call timer_start(500, { tid -> feedkeys("\<C-w>j", 'tx') })
2266  call timer_start(1500, { tid -> feedkeys("\<C-l>", 'tx') })
2267  au BufLeave * if &buftype == 'terminal' | silent! normal i | endif
2268
2269  sleep 2
2270  exe tbuf . 'bwipe!'
2271  au! BufLeave
2272  set statusline=
2273endfunc
2274
2275func Test_terminal_getwinpos()
2276  CheckRunVimInTerminal
2277
2278  " split, go to the bottom-right window
2279  split
2280  wincmd j
2281  set splitright
2282
2283  call writefile([
2284	\ 'echo getwinpos()',
2285	\ ], 'XTest_getwinpos')
2286  let buf = RunVimInTerminal('-S XTest_getwinpos', {'cols': 60})
2287  call TermWait(buf)
2288
2289  " Find the output of getwinpos() in the bottom line.
2290  let rows = term_getsize(buf)[0]
2291  call WaitForAssert({-> assert_match('\[\d\+, \d\+\]', term_getline(buf, rows))})
2292  let line = term_getline(buf, rows)
2293  let xpos = str2nr(substitute(line, '\[\(\d\+\), \d\+\]', '\1', ''))
2294  let ypos = str2nr(substitute(line, '\[\d\+, \(\d\+\)\]', '\1', ''))
2295
2296  " Position must be bigger than the getwinpos() result of Vim itself.
2297  " The calculation in the console assumes a 10 x 7 character cell.
2298  " In the GUI it can be more, let's assume a 20 x 14 cell.
2299  " And then add 100 / 200 tolerance.
2300  let [xroot, yroot] = getwinpos()
2301  let winpos = 50->getwinpos()
2302  call assert_equal(xroot, winpos[0])
2303  call assert_equal(yroot, winpos[1])
2304  let [winrow, wincol] = win_screenpos('.')
2305  let xoff = wincol * (has('gui_running') ? 14 : 7) + 100
2306  let yoff = winrow * (has('gui_running') ? 20 : 10) + 200
2307  call assert_inrange(xroot + 2, xroot + xoff, xpos)
2308  call assert_inrange(yroot + 2, yroot + yoff, ypos)
2309
2310  call TermWait(buf)
2311  call term_sendkeys(buf, ":q\<CR>")
2312  call StopVimInTerminal(buf)
2313  call delete('XTest_getwinpos')
2314  exe buf . 'bwipe!'
2315  set splitright&
2316  only!
2317endfunc
2318
2319func Test_terminal_altscreen()
2320  " somehow doesn't work on MS-Windows
2321  CheckUnix
2322  let cmd = "cat Xtext\<CR>"
2323
2324  let buf = term_start(&shell, {})
2325  call writefile(["\<Esc>[?1047h"], 'Xtext')
2326  call term_sendkeys(buf, cmd)
2327  call WaitForAssert({-> assert_equal(1, term_getaltscreen(buf))})
2328
2329  call writefile(["\<Esc>[?1047l"], 'Xtext')
2330  call term_sendkeys(buf, cmd)
2331  call WaitForAssert({-> assert_equal(0, term_getaltscreen(buf))})
2332
2333  call term_sendkeys(buf, "exit\r")
2334  exe buf . "bwipe!"
2335  call delete('Xtext')
2336endfunc
2337
2338func Test_terminal_shell_option()
2339  if has('unix')
2340    " exec is a shell builtin command, should fail without a shell.
2341    term exec ls runtest.vim
2342    call WaitForAssert({-> assert_match('job failed', term_getline(bufnr(), 1))})
2343    bwipe!
2344
2345    term ++shell exec ls runtest.vim
2346    call WaitForAssert({-> assert_match('runtest.vim', term_getline(bufnr(), 1))})
2347    bwipe!
2348  elseif has('win32')
2349    " dir is a shell builtin command, should fail without a shell.
2350    try
2351      term dir /b runtest.vim
2352      call WaitForAssert({-> assert_match('job failed\|cannot access .*: No such file or directory', term_getline(bufnr(), 1))})
2353    catch /CreateProcess/
2354      " ignore
2355    endtry
2356    bwipe!
2357
2358    term ++shell dir /b runtest.vim
2359    call WaitForAssert({-> assert_match('runtest.vim', term_getline(bufnr(), 1))})
2360    bwipe!
2361  endif
2362endfunc
2363
2364func Test_terminal_setapi_and_call()
2365  CheckRunVimInTerminal
2366
2367  call WriteApiCall('Tapi_TryThis')
2368  call ch_logfile('Xlog', 'w')
2369
2370  unlet! g:called_bufnum
2371  unlet! g:called_arg
2372
2373  let buf = RunVimInTerminal('-S Xscript', {'term_api': ''})
2374  call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))})
2375  call assert_false(exists('g:called_bufnum'))
2376  call assert_false(exists('g:called_arg'))
2377
2378  eval buf->term_setapi('Tapi_')
2379  call term_sendkeys(buf, ":set notitle\<CR>")
2380  call term_sendkeys(buf, ":source Xscript\<CR>")
2381  call WaitFor({-> exists('g:called_bufnum')})
2382  call assert_equal(buf, g:called_bufnum)
2383  call assert_equal(['hello', 123], g:called_arg)
2384
2385  call StopVimInTerminal(buf)
2386
2387  call delete('Xscript')
2388  call ch_logfile('')
2389  call delete('Xlog')
2390  unlet! g:called_bufnum
2391  unlet! g:called_arg
2392endfunc
2393
2394func Test_terminal_api_arg()
2395  CheckRunVimInTerminal
2396
2397  call WriteApiCall('Tapi_TryThis')
2398  call ch_logfile('Xlog', 'w')
2399
2400  unlet! g:called_bufnum
2401  unlet! g:called_arg
2402
2403  execute 'term ++api= ' .. GetVimCommandCleanTerm() .. '-S Xscript'
2404  let buf = bufnr('%')
2405  call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))})
2406  call assert_false(exists('g:called_bufnum'))
2407  call assert_false(exists('g:called_arg'))
2408
2409  call StopVimInTerminal(buf)
2410
2411  call ch_logfile('Xlog', 'w')
2412
2413  execute 'term ++api=Tapi_ ' .. GetVimCommandCleanTerm() .. '-S Xscript'
2414  let buf = bufnr('%')
2415  call WaitFor({-> exists('g:called_bufnum')})
2416  call assert_equal(buf, g:called_bufnum)
2417  call assert_equal(['hello', 123], g:called_arg)
2418
2419  call StopVimInTerminal(buf)
2420
2421  call delete('Xscript')
2422  call ch_logfile('')
2423  call delete('Xlog')
2424  unlet! g:called_bufnum
2425  unlet! g:called_arg
2426endfunc
2427
2428func Test_terminal_invalid_arg()
2429  call assert_fails('terminal ++xyz', 'E181:')
2430endfunc
2431
2432func Test_terminal_in_popup()
2433  CheckRunVimInTerminal
2434
2435  let text =<< trim END
2436    some text
2437    to edit
2438    in a popup window
2439  END
2440  call writefile(text, 'Xtext')
2441  let cmd = GetVimCommandCleanTerm()
2442  let lines = [
2443	\ 'set t_u7=',
2444	\ 'call setline(1, range(20))',
2445	\ 'hi PopTerm ctermbg=grey',
2446	\ 'func OpenTerm(setColor)',
2447	\ "  set noruler",
2448	\ "  let s:buf = term_start('" .. cmd .. " Xtext', #{hidden: 1, term_finish: 'close'})",
2449	\ '  let g:winid = popup_create(s:buf, #{minwidth: 45, minheight: 7, border: [], drag: 1, resize: 1})',
2450	\ '  if a:setColor',
2451	\ '    call win_execute(g:winid, "set wincolor=PopTerm")',
2452	\ '  endif',
2453	\ 'endfunc',
2454	\ 'func HidePopup()',
2455	\ '  call popup_hide(g:winid)',
2456	\ 'endfunc',
2457	\ 'func ClosePopup()',
2458	\ '  call popup_close(g:winid)',
2459	\ 'endfunc',
2460	\ 'func ReopenPopup()',
2461	\ '  call popup_create(s:buf, #{minwidth: 40, minheight: 6, border: []})',
2462	\ 'endfunc',
2463	\ ]
2464  call writefile(lines, 'XtermPopup')
2465  let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15})
2466  call TermWait(buf, 100)
2467  call term_sendkeys(buf, ":call OpenTerm(0)\<CR>")
2468  call TermWait(buf, 100)
2469  call term_sendkeys(buf, ":\<CR>")
2470  call TermWait(buf, 100)
2471  call term_sendkeys(buf, "\<C-W>:echo getwinvar(g:winid, \"&buftype\") win_gettype(g:winid)\<CR>")
2472  call VerifyScreenDump(buf, 'Test_terminal_popup_1', {})
2473
2474  call term_sendkeys(buf, ":q\<CR>")
2475  call VerifyScreenDump(buf, 'Test_terminal_popup_2', {})
2476
2477  call term_sendkeys(buf, ":call OpenTerm(1)\<CR>")
2478  call TermWait(buf, 150)
2479  call term_sendkeys(buf, ":set hlsearch\<CR>")
2480  call term_sendkeys(buf, "/edit\<CR>")
2481  call VerifyScreenDump(buf, 'Test_terminal_popup_3', {})
2482
2483  call term_sendkeys(buf, "\<C-W>:call HidePopup()\<CR>")
2484  call VerifyScreenDump(buf, 'Test_terminal_popup_4', {})
2485  call term_sendkeys(buf, "\<CR>")
2486  call TermWait(buf, 50)
2487
2488  call term_sendkeys(buf, "\<C-W>:call ClosePopup()\<CR>")
2489  call VerifyScreenDump(buf, 'Test_terminal_popup_5', {})
2490
2491  call term_sendkeys(buf, "\<C-W>:call ReopenPopup()\<CR>")
2492  call VerifyScreenDump(buf, 'Test_terminal_popup_6', {})
2493
2494  " Go to terminal-Normal mode and visually select text.
2495  call term_sendkeys(buf, "\<C-W>Ngg/in\<CR>vww")
2496  call VerifyScreenDump(buf, 'Test_terminal_popup_7', {})
2497
2498  " Back to job mode, redraws
2499  call term_sendkeys(buf, "A")
2500  call VerifyScreenDump(buf, 'Test_terminal_popup_8', {})
2501
2502  call TermWait(buf, 50)
2503  call term_sendkeys(buf, ":q\<CR>")
2504  call TermWait(buf, 100)  " wait for terminal to vanish
2505
2506  call StopVimInTerminal(buf)
2507  call delete('Xtext')
2508  call delete('XtermPopup')
2509endfunc
2510
2511" Check a terminal in popup window uses the default mininum size.
2512func Test_terminal_in_popup_min_size()
2513  CheckRunVimInTerminal
2514
2515  let text =<< trim END
2516    another text
2517    to show
2518    in a popup window
2519  END
2520  call writefile(text, 'Xtext')
2521  let lines = [
2522	\ 'set t_u7=',
2523	\ 'call setline(1, range(20))',
2524	\ 'func OpenTerm()',
2525	\ "  let s:buf = term_start('cat Xtext', #{hidden: 1})",
2526	\ '  let g:winid = popup_create(s:buf, #{ border: []})',
2527	\ 'endfunc',
2528	\ ]
2529  call writefile(lines, 'XtermPopup')
2530  let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15})
2531  call TermWait(buf, 100)
2532  call term_sendkeys(buf, ":set noruler\<CR>")
2533  call term_sendkeys(buf, ":call OpenTerm()\<CR>")
2534  call TermWait(buf, 50)
2535  call term_sendkeys(buf, ":\<CR>")
2536  call VerifyScreenDump(buf, 'Test_terminal_popup_m1', {})
2537
2538  call TermWait(buf, 50)
2539  call term_sendkeys(buf, ":q\<CR>")
2540  call TermWait(buf, 50)  " wait for terminal to vanish
2541  call StopVimInTerminal(buf)
2542  call delete('Xtext')
2543  call delete('XtermPopup')
2544endfunc
2545
2546" Check a terminal in popup window with different colors
2547func Terminal_in_popup_colored(group_name, highlight_cmd, highlight_opt)
2548  CheckRunVimInTerminal
2549  CheckUnix
2550
2551  let lines = [
2552	\ 'set t_u7=',
2553	\ 'call setline(1, range(20))',
2554	\ 'func OpenTerm()',
2555	\ "  let s:buf = term_start('cat', #{hidden: 1, "
2556	\ .. a:highlight_opt .. "})",
2557	\ '  let g:winid = popup_create(s:buf, #{ border: []})',
2558	\ 'endfunc',
2559	\ a:highlight_cmd,
2560	\ ]
2561  call writefile(lines, 'XtermPopup')
2562  let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15})
2563  call TermWait(buf, 100)
2564  call term_sendkeys(buf, ":set noruler\<CR>")
2565  call term_sendkeys(buf, ":call OpenTerm()\<CR>")
2566  call TermWait(buf, 50)
2567  call term_sendkeys(buf, "hello\<CR>")
2568  call VerifyScreenDump(buf, 'Test_terminal_popup_' .. a:group_name, {})
2569
2570  call term_sendkeys(buf, "\<C-D>")
2571  call TermWait(buf, 50)
2572  call term_sendkeys(buf, ":q\<CR>")
2573  call TermWait(buf, 50)  " wait for terminal to vanish
2574  call StopVimInTerminal(buf)
2575  call delete('XtermPopup')
2576endfunc
2577
2578func Test_terminal_in_popup_colored_Terminal()
2579  call Terminal_in_popup_colored("Terminal", "highlight Terminal ctermfg=blue ctermbg=yellow", "")
2580endfunc
2581
2582func Test_terminal_in_popup_colored_group()
2583  call Terminal_in_popup_colored("MyTermCol", "highlight MyTermCol ctermfg=darkgreen ctermbg=lightblue", "term_highlight: 'MyTermCol',")
2584endfunc
2585
2586func Test_double_popup_terminal()
2587  let buf1 = term_start(&shell, #{hidden: 1})
2588  let win1 = popup_create(buf1, {})
2589  let buf2 = term_start(&shell, #{hidden: 1})
2590  let win2 = popup_create(buf2, {})
2591  call popup_close(win1)
2592  call popup_close(win2)
2593  exe buf1 .. 'bwipe!'
2594  exe buf2 .. 'bwipe!'
2595endfunc
2596
2597func Test_issue_5607()
2598  let wincount = winnr('$')
2599  exe 'terminal' &shell &shellcmdflag 'exit'
2600  let job = term_getjob(bufnr())
2601  call WaitForAssert({-> assert_equal("dead", job_status(job))})
2602
2603  let old_wincolor = &wincolor
2604  try
2605    set wincolor=
2606  finally
2607    let &wincolor = old_wincolor
2608    bw!
2609  endtry
2610endfunc
2611
2612func Test_hidden_terminal()
2613  let buf = term_start(&shell, #{hidden: 1})
2614  call assert_equal('', bufname('^$'))
2615  call StopShellInTerminal(buf)
2616endfunc
2617
2618func Test_term_nasty_callback()
2619  CheckExecutable sh
2620
2621  set hidden
2622  let g:buf0 = term_start('sh', #{hidden: 1})
2623  call popup_create(g:buf0, {})
2624  let g:buf1 = term_start('sh', #{hidden: 1, term_finish: 'close'})
2625  call popup_create(g:buf1, {})
2626  call assert_fails("call term_start(['sh', '-c'], #{curwin: 1})", 'E863:')
2627
2628  call popup_clear(1)
2629  set hidden&
2630endfunc
2631
2632func Test_term_and_startinsert()
2633  CheckRunVimInTerminal
2634  CheckUnix
2635
2636  let lines =<< trim EOL
2637     put='some text'
2638     term
2639     startinsert
2640  EOL
2641  call writefile(lines, 'XTest_startinsert')
2642  let buf = RunVimInTerminal('-S XTest_startinsert', {})
2643
2644  call term_sendkeys(buf, "exit\r")
2645  call WaitForAssert({-> assert_equal("some text", term_getline(buf, 1))})
2646  call term_sendkeys(buf, "0l")
2647  call term_sendkeys(buf, "A<\<Esc>")
2648  call WaitForAssert({-> assert_equal("some text<", term_getline(buf, 1))})
2649
2650  call StopVimInTerminal(buf)
2651  call delete('XTest_startinsert')
2652endfunc
2653
2654" Test for passing invalid arguments to terminal functions
2655func Test_term_func_invalid_arg()
2656  call assert_fails('let b = term_getaltscreen([])', 'E745:')
2657  call assert_fails('let p = term_getansicolors([])', 'E745:')
2658  call assert_fails('let a = term_getattr(1, [])', 'E730:')
2659  call assert_fails('let c = term_getcursor([])', 'E745:')
2660  call assert_fails('let l = term_getline([], 1)', 'E745:')
2661  call assert_fails('let l = term_getscrolled([])', 'E745:')
2662  call assert_fails('let s = term_getsize([])', 'E745:')
2663  call assert_fails('let s = term_getstatus([])', 'E745:')
2664  call assert_fails('let s = term_scrape([], 1)', 'E745:')
2665  call assert_fails('call term_sendkeys([], "a")', 'E745:')
2666  call assert_fails('call term_setansicolors([], [])', 'E745:')
2667  call assert_fails('call term_setapi([], "")', 'E745:')
2668  call assert_fails('call term_setrestore([], "")', 'E745:')
2669  call assert_fails('call term_setkill([], "")', 'E745:')
2670endfunc
2671
2672" Test for sending various special keycodes to a terminal
2673func Test_term_keycode_translation()
2674  CheckRunVimInTerminal
2675
2676  let buf = RunVimInTerminal('', {})
2677  call term_sendkeys(buf, ":set nocompatible\<CR>")
2678
2679  let keys = ["\<F1>", "\<F2>", "\<F3>", "\<F4>", "\<F5>", "\<F6>", "\<F7>",
2680        \ "\<F8>", "\<F9>", "\<F10>", "\<F11>", "\<F12>", "\<Home>",
2681        \ "\<S-Home>", "\<C-Home>", "\<End>", "\<S-End>", "\<C-End>",
2682	\ "\<Ins>", "\<Del>", "\<Left>", "\<S-Left>", "\<C-Left>", "\<Right>",
2683        \ "\<S-Right>", "\<C-Right>", "\<Up>", "\<S-Up>", "\<Down>",
2684        \ "\<S-Down>"]
2685  let output = ['<F1>', '<F2>', '<F3>', '<F4>', '<F5>', '<F6>', '<F7>',
2686        \ '<F8>', '<F9>', '<F10>', '<F11>', '<F12>', '<Home>', '<S-Home>',
2687        \ '<C-Home>', '<End>', '<S-End>', '<C-End>', '<Insert>', '<Del>',
2688        \ '<Left>', '<S-Left>', '<C-Left>', '<Right>', '<S-Right>',
2689        \ '<C-Right>', '<Up>', '<S-Up>', '<Down>', '<S-Down>',
2690        \ '0123456789', "\t\t.+-*/"]
2691
2692  for k in keys
2693    call term_sendkeys(buf, "i\<C-K>" .. k .. "\<CR>\<C-\>\<C-N>")
2694  endfor
2695  call term_sendkeys(buf, "i\<K0>\<K1>\<K2>\<K3>\<K4>\<K5>\<K6>\<K7>")
2696  call term_sendkeys(buf, "\<K8>\<K9>\<kEnter>\<kPoint>\<kPlus>")
2697  call term_sendkeys(buf, "\<kMinus>\<kMultiply>\<kDivide>\<C-\>\<C-N>")
2698  call term_sendkeys(buf, "\<Home>\<Ins>\<Tab>\<S-Tab>\<C-\>\<C-N>")
2699
2700  call term_sendkeys(buf, ":write Xkeycodes\<CR>")
2701  call term_wait(buf)
2702  call StopVimInTerminal(buf)
2703  call assert_equal(output, readfile('Xkeycodes'))
2704  call delete('Xkeycodes')
2705endfunc
2706
2707" Test for using the mouse in a terminal
2708func Test_term_mouse()
2709  CheckNotGui
2710  CheckRunVimInTerminal
2711
2712  let save_mouse = &mouse
2713  let save_term = &term
2714  let save_ttymouse = &ttymouse
2715  let save_clipboard = &clipboard
2716  call test_override('no_query_mouse', 1)
2717  set mouse=a term=xterm ttymouse=sgr mousetime=200 clipboard=
2718
2719  let lines =<< trim END
2720    one two three four five
2721    red green yellow red blue
2722    vim emacs sublime nano
2723  END
2724  call writefile(lines, 'Xtest_mouse')
2725
2726  let buf = RunVimInTerminal('Xtest_mouse -n', {})
2727  call term_sendkeys(buf, ":set nocompatible\<CR>")
2728  call term_sendkeys(buf, ":set mouse=a term=xterm ttymouse=sgr\<CR>")
2729  call term_sendkeys(buf, ":set clipboard=\<CR>")
2730  call term_sendkeys(buf, ":set mousemodel=extend\<CR>")
2731  call term_wait(buf)
2732  redraw!
2733
2734  " Test for <LeftMouse> click/release
2735  call test_setmouse(2, 5)
2736  call feedkeys("\<LeftMouse>\<LeftRelease>", 'xt')
2737  call test_setmouse(3, 8)
2738  call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>")
2739  call term_wait(buf, 50)
2740  call term_sendkeys(buf, ":call writefile([json_encode(getpos('.'))], 'Xbuf')\<CR>")
2741  call term_wait(buf, 50)
2742  let pos = json_decode(readfile('Xbuf')[0])
2743  call assert_equal([3, 8], pos[1:2])
2744
2745  " Test for selecting text using mouse
2746  call delete('Xbuf')
2747  call test_setmouse(2, 11)
2748  call term_sendkeys(buf, "\<LeftMouse>")
2749  call test_setmouse(2, 16)
2750  call term_sendkeys(buf, "\<LeftRelease>y")
2751  call term_wait(buf, 50)
2752  call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>")
2753  call term_wait(buf, 50)
2754  call assert_equal('yellow', readfile('Xbuf')[0])
2755
2756  " Test for selecting text using doubleclick
2757  call delete('Xbuf')
2758  call test_setmouse(1, 11)
2759  call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>\<LeftMouse>")
2760  call test_setmouse(1, 17)
2761  call term_sendkeys(buf, "\<LeftRelease>y")
2762  call term_wait(buf, 50)
2763  call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>")
2764  call term_wait(buf, 50)
2765  call assert_equal('three four', readfile('Xbuf')[0])
2766
2767  " Test for selecting a line using triple click
2768  call delete('Xbuf')
2769  call test_setmouse(3, 2)
2770  call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>\<LeftMouse>\<LeftRelease>\<LeftMouse>\<LeftRelease>y")
2771  call term_wait(buf, 50)
2772  call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>")
2773  call term_wait(buf, 50)
2774  call assert_equal("vim emacs sublime nano\n", readfile('Xbuf')[0])
2775
2776  " Test for selecting a block using qudraple click
2777  call delete('Xbuf')
2778  call test_setmouse(1, 11)
2779  call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>\<LeftMouse>\<LeftRelease>\<LeftMouse>\<LeftRelease>\<LeftMouse>")
2780  call test_setmouse(3, 13)
2781  call term_sendkeys(buf, "\<LeftRelease>y")
2782  call term_wait(buf, 50)
2783  call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>")
2784  call term_wait(buf, 50)
2785  call assert_equal("ree\nyel\nsub", readfile('Xbuf')[0])
2786
2787  " Test for extending a selection using right click
2788  call delete('Xbuf')
2789  call test_setmouse(2, 9)
2790  call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>")
2791  call test_setmouse(2, 16)
2792  call term_sendkeys(buf, "\<RightMouse>\<RightRelease>y")
2793  call term_wait(buf, 50)
2794  call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>")
2795  call term_wait(buf, 50)
2796  call assert_equal("n yellow", readfile('Xbuf')[0])
2797
2798  " Test for pasting text using middle click
2799  call delete('Xbuf')
2800  call term_sendkeys(buf, ":let @r='bright '\<CR>")
2801  call test_setmouse(2, 22)
2802  call term_sendkeys(buf, "\"r\<MiddleMouse>\<MiddleRelease>")
2803  call term_wait(buf, 50)
2804  call term_sendkeys(buf, ":call writefile([getline(2)], 'Xbuf')\<CR>")
2805  call term_wait(buf, 50)
2806  call assert_equal("red bright blue", readfile('Xbuf')[0][-15:])
2807
2808  " cleanup
2809  call term_wait(buf)
2810  call StopVimInTerminal(buf)
2811  let &mouse = save_mouse
2812  let &term = save_term
2813  let &ttymouse = save_ttymouse
2814  let &clipboard = save_clipboard
2815  set mousetime&
2816  call test_override('no_query_mouse', 0)
2817  call delete('Xtest_mouse')
2818  call delete('Xbuf')
2819endfunc
2820
2821" Test for modeless selection in a terminal
2822func Test_term_modeless_selection()
2823  CheckUnix
2824  CheckNotGui
2825  CheckRunVimInTerminal
2826  CheckFeature clipboard_working
2827
2828  let save_mouse = &mouse
2829  let save_term = &term
2830  let save_ttymouse = &ttymouse
2831  call test_override('no_query_mouse', 1)
2832  set mouse=a term=xterm ttymouse=sgr mousetime=200
2833  set clipboard=autoselectml
2834
2835  let lines =<< trim END
2836    one two three four five
2837    red green yellow red blue
2838    vim emacs sublime nano
2839  END
2840  call writefile(lines, 'Xtest_modeless')
2841
2842  let buf = RunVimInTerminal('Xtest_modeless -n', {})
2843  call term_sendkeys(buf, ":set nocompatible\<CR>")
2844  call term_sendkeys(buf, ":set mouse=\<CR>")
2845  call term_wait(buf)
2846  redraw!
2847
2848  " Test for copying a modeless selection to clipboard
2849  let @* = 'clean'
2850  " communicating with X server may take a little time
2851  sleep 100m
2852  call feedkeys(MouseLeftClickCode(2, 3), 'x')
2853  call feedkeys(MouseLeftDragCode(2, 11), 'x')
2854  call feedkeys(MouseLeftReleaseCode(2, 11), 'x')
2855  call assert_equal("d green y", @*)
2856
2857  " cleanup
2858  call term_wait(buf)
2859  call StopVimInTerminal(buf)
2860  let &mouse = save_mouse
2861  let &term = save_term
2862  let &ttymouse = save_ttymouse
2863  set mousetime& clipboard&
2864  call test_override('no_query_mouse', 0)
2865  call delete('Xtest_modeless')
2866endfunc
2867
2868" vim: shiftwidth=2 sts=2 expandtab
2869