1" Tests for the terminal window.
2
3if !has('terminal')
4  finish
5endif
6
7source shared.vim
8source screendump.vim
9
10let s:python = PythonProg()
11
12" Open a terminal with a shell, assign the job to g:job and return the buffer
13" number.
14func Run_shell_in_terminal(options)
15  if has('win32')
16    let buf = term_start([&shell,'/k'], a:options)
17  else
18    let buf = term_start(&shell, a:options)
19  endif
20
21  let termlist = term_list()
22  call assert_equal(1, len(termlist))
23  call assert_equal(buf, termlist[0])
24
25  let g:job = term_getjob(buf)
26  call assert_equal(v:t_job, type(g:job))
27
28  let string = string({'job': term_getjob(buf)})
29  call assert_match("{'job': 'process \\d\\+ run'}", string)
30
31  return buf
32endfunc
33
34func Test_terminal_basic()
35  au BufWinEnter * if &buftype == 'terminal' | let b:done = 'yes' | endif
36  let buf = Run_shell_in_terminal({})
37
38  if has("unix")
39    call assert_match('^/dev/', job_info(g:job).tty_out)
40    call assert_match('^/dev/', term_gettty(''))
41  else
42    call assert_match('^\\\\.\\pipe\\', job_info(g:job).tty_out)
43    call assert_match('^\\\\.\\pipe\\', term_gettty(''))
44  endif
45  call assert_equal('t', mode())
46  call assert_equal('yes', b:done)
47  call assert_match('%aR[^\n]*running]', execute('ls'))
48  call assert_match('%aR[^\n]*running]', execute('ls R'))
49  call assert_notmatch('%[^\n]*running]', execute('ls F'))
50  call assert_notmatch('%[^\n]*running]', execute('ls ?'))
51
52  call Stop_shell_in_terminal(buf)
53  call term_wait(buf)
54  call assert_equal('n', mode())
55  call assert_match('%aF[^\n]*finished]', execute('ls'))
56  call assert_match('%aF[^\n]*finished]', execute('ls F'))
57  call assert_notmatch('%[^\n]*finished]', execute('ls R'))
58  call assert_notmatch('%[^\n]*finished]', execute('ls ?'))
59
60  " closing window wipes out the terminal buffer a with finished job
61  close
62  call assert_equal("", bufname(buf))
63
64  au! BufWinEnter
65  unlet g:job
66endfunc
67
68func Test_terminal_make_change()
69  let buf = Run_shell_in_terminal({})
70  call Stop_shell_in_terminal(buf)
71  call term_wait(buf)
72
73  setlocal modifiable
74  exe "normal Axxx\<Esc>"
75  call assert_fails(buf . 'bwipe', 'E517')
76  undo
77
78  exe buf . 'bwipe'
79  unlet g:job
80endfunc
81
82func Test_terminal_wipe_buffer()
83  let buf = Run_shell_in_terminal({})
84  call assert_fails(buf . 'bwipe', 'E517')
85  exe buf . 'bwipe!'
86  call WaitFor('job_status(g:job) == "dead"')
87  call assert_equal('dead', job_status(g:job))
88  call assert_equal("", bufname(buf))
89
90  unlet g:job
91endfunc
92
93func Test_terminal_split_quit()
94  let buf = Run_shell_in_terminal({})
95  call term_wait(buf)
96  split
97  quit!
98  call term_wait(buf)
99  sleep 50m
100  call assert_equal('run', job_status(g:job))
101
102  quit!
103  call WaitFor('job_status(g:job) == "dead"')
104  call assert_equal('dead', job_status(g:job))
105
106  exe buf . 'bwipe'
107  unlet g:job
108endfunc
109
110func Test_terminal_hide_buffer()
111  let buf = Run_shell_in_terminal({})
112  setlocal bufhidden=hide
113  quit
114  for nr in range(1, winnr('$'))
115    call assert_notequal(winbufnr(nr), buf)
116  endfor
117  call assert_true(bufloaded(buf))
118  call assert_true(buflisted(buf))
119
120  exe 'split ' . buf . 'buf'
121  call Stop_shell_in_terminal(buf)
122  exe buf . 'bwipe'
123
124  unlet g:job
125endfunc
126
127func! s:Nasty_exit_cb(job, st)
128  exe g:buf . 'bwipe!'
129  let g:buf = 0
130endfunc
131
132func Get_cat_123_cmd()
133  if has('win32')
134    return 'cmd /c "cls && color 2 && echo 123"'
135  else
136    call writefile(["\<Esc>[32m123"], 'Xtext')
137    return "cat Xtext"
138  endif
139endfunc
140
141func Test_terminal_nasty_cb()
142  let cmd = Get_cat_123_cmd()
143  let g:buf = term_start(cmd, {'exit_cb': function('s:Nasty_exit_cb')})
144  let g:job = term_getjob(g:buf)
145
146  call WaitFor('job_status(g:job) == "dead"')
147  call WaitFor('g:buf == 0')
148  unlet g:buf
149  unlet g:job
150  call delete('Xtext')
151endfunc
152
153func Check_123(buf)
154  let l = term_scrape(a:buf, 0)
155  call assert_true(len(l) == 0)
156  let l = term_scrape(a:buf, 999)
157  call assert_true(len(l) == 0)
158  let l = term_scrape(a:buf, 1)
159  call assert_true(len(l) > 0)
160  call assert_equal('1', l[0].chars)
161  call assert_equal('2', l[1].chars)
162  call assert_equal('3', l[2].chars)
163  call assert_equal('#00e000', l[0].fg)
164  if &background == 'light'
165    call assert_equal('#ffffff', l[0].bg)
166  else
167    call assert_equal('#000000', l[0].bg)
168  endif
169
170  let l = term_getline(a:buf, -1)
171  call assert_equal('', l)
172  let l = term_getline(a:buf, 0)
173  call assert_equal('', l)
174  let l = term_getline(a:buf, 999)
175  call assert_equal('', l)
176  let l = term_getline(a:buf, 1)
177  call assert_equal('123', l)
178endfunc
179
180func Test_terminal_scrape_123()
181  let cmd = Get_cat_123_cmd()
182  let buf = term_start(cmd)
183
184  let termlist = term_list()
185  call assert_equal(1, len(termlist))
186  call assert_equal(buf, termlist[0])
187
188  " Nothing happens with invalid buffer number
189  call term_wait(1234)
190
191  call term_wait(buf)
192  " On MS-Windows we first get a startup message of two lines, wait for the
193  " "cls" to happen, after that we have one line with three characters.
194  call WaitFor({-> len(term_scrape(buf, 1)) == 3})
195  call Check_123(buf)
196
197  " Must still work after the job ended.
198  let job = term_getjob(buf)
199  call WaitFor({-> job_status(job) == "dead"})
200  call term_wait(buf)
201  call Check_123(buf)
202
203  exe buf . 'bwipe'
204  call delete('Xtext')
205endfunc
206
207func Test_terminal_scrape_multibyte()
208  if !has('multi_byte')
209    return
210  endif
211  call writefile(["léttまrs"], 'Xtext')
212  if has('win32')
213    " Run cmd with UTF-8 codepage to make the type command print the expected
214    " multibyte characters.
215    let buf = term_start("cmd /K chcp 65001")
216    call term_sendkeys(buf, "type Xtext\<CR>")
217    call term_sendkeys(buf, "exit\<CR>")
218    let line = 4
219  else
220    let buf = term_start("cat Xtext")
221    let line = 1
222  endif
223
224  call WaitFor({-> len(term_scrape(buf, line)) >= 7 && term_scrape(buf, line)[0].chars == "l"})
225  let l = term_scrape(buf, line)
226  call assert_true(len(l) >= 7)
227  call assert_equal('l', l[0].chars)
228  call assert_equal('é', l[1].chars)
229  call assert_equal(1, l[1].width)
230  call assert_equal('t', l[2].chars)
231  call assert_equal('t', l[3].chars)
232  call assert_equal('ま', l[4].chars)
233  call assert_equal(2, l[4].width)
234  call assert_equal('r', l[5].chars)
235  call assert_equal('s', l[6].chars)
236
237  let job = term_getjob(buf)
238  call WaitFor({-> job_status(job) == "dead"})
239  call term_wait(buf)
240
241  exe buf . 'bwipe'
242  call delete('Xtext')
243endfunc
244
245func Test_terminal_scroll()
246  call writefile(range(1, 200), 'Xtext')
247  if has('win32')
248    let cmd = 'cmd /c "type Xtext"'
249  else
250    let cmd = "cat Xtext"
251  endif
252  let buf = term_start(cmd)
253
254  let job = term_getjob(buf)
255  call WaitFor({-> job_status(job) == "dead"})
256  call term_wait(buf)
257  if has('win32')
258    " TODO: this should not be needed
259    sleep 100m
260  endif
261
262  let scrolled = term_getscrolled(buf)
263  call assert_equal('1', getline(1))
264  call assert_equal('1', term_getline(buf, 1 - scrolled))
265  call assert_equal('49', getline(49))
266  call assert_equal('49', term_getline(buf, 49 - scrolled))
267  call assert_equal('200', getline(200))
268  call assert_equal('200', term_getline(buf, 200 - scrolled))
269
270  exe buf . 'bwipe'
271  call delete('Xtext')
272endfunc
273
274func Test_terminal_size()
275  let cmd = Get_cat_123_cmd()
276
277  exe 'terminal ++rows=5 ' . cmd
278  let size = term_getsize('')
279  bwipe!
280  call assert_equal(5, size[0])
281
282  call term_start(cmd, {'term_rows': 6})
283  let size = term_getsize('')
284  bwipe!
285  call assert_equal(6, size[0])
286
287  vsplit
288  exe 'terminal ++rows=5 ++cols=33 ' . cmd
289  let size = term_getsize('')
290  bwipe!
291  call assert_equal([5, 33], size)
292
293  call term_start(cmd, {'term_rows': 6, 'term_cols': 36})
294  let size = term_getsize('')
295  bwipe!
296  call assert_equal([6, 36], size)
297
298  exe 'vertical terminal ++cols=20 ' . cmd
299  let size = term_getsize('')
300  bwipe!
301  call assert_equal(20, size[1])
302
303  call term_start(cmd, {'vertical': 1, 'term_cols': 26})
304  let size = term_getsize('')
305  bwipe!
306  call assert_equal(26, size[1])
307
308  split
309  exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd
310  let size = term_getsize('')
311  bwipe!
312  call assert_equal([6, 20], size)
313
314  call term_start(cmd, {'vertical': 1, 'term_rows': 7, 'term_cols': 27})
315  let size = term_getsize('')
316  bwipe!
317  call assert_equal([7, 27], size)
318
319  call delete('Xtext')
320endfunc
321
322func Test_terminal_curwin()
323  let cmd = Get_cat_123_cmd()
324  call assert_equal(1, winnr('$'))
325
326  split dummy
327  exe 'terminal ++curwin ' . cmd
328  call assert_equal(2, winnr('$'))
329  bwipe!
330
331  split dummy
332  call term_start(cmd, {'curwin': 1})
333  call assert_equal(2, winnr('$'))
334  bwipe!
335
336  split dummy
337  call setline(1, 'change')
338  call assert_fails('terminal ++curwin ' . cmd, 'E37:')
339  call assert_equal(2, winnr('$'))
340  exe 'terminal! ++curwin ' . cmd
341  call assert_equal(2, winnr('$'))
342  bwipe!
343
344  split dummy
345  call setline(1, 'change')
346  call assert_fails("call term_start(cmd, {'curwin': 1})", 'E37:')
347  call assert_equal(2, winnr('$'))
348  bwipe!
349
350  split dummy
351  bwipe!
352  call delete('Xtext')
353endfunc
354
355func s:get_sleep_cmd()
356  if s:python != ''
357    let cmd = s:python . " test_short_sleep.py"
358    let waittime = 500
359  else
360    echo 'This will take five seconds...'
361    let waittime = 2000
362    if has('win32')
363      let cmd = $windir . '\system32\timeout.exe 1'
364    else
365      let cmd = 'sleep 1'
366    endif
367  endif
368  return [cmd, waittime]
369endfunc
370
371func Test_terminal_finish_open_close()
372  call assert_equal(1, winnr('$'))
373
374  let [cmd, waittime] = s:get_sleep_cmd()
375
376  " shell terminal closes automatically
377  terminal
378  let buf = bufnr('%')
379  call assert_equal(2, winnr('$'))
380  " Wait for the shell to display a prompt
381  call WaitFor({-> term_getline(buf, 1) != ""})
382  call Stop_shell_in_terminal(buf)
383  call WaitFor("winnr('$') == 1", waittime)
384
385  " shell terminal that does not close automatically
386  terminal ++noclose
387  let buf = bufnr('%')
388  call assert_equal(2, winnr('$'))
389  " Wait for the shell to display a prompt
390  call WaitFor({-> term_getline(buf, 1) != ""})
391  call Stop_shell_in_terminal(buf)
392  call assert_equal(2, winnr('$'))
393  quit
394  call assert_equal(1, winnr('$'))
395
396  exe 'terminal ++close ' . cmd
397  call assert_equal(2, winnr('$'))
398  wincmd p
399  call WaitFor("winnr('$') == 1", waittime)
400
401  call term_start(cmd, {'term_finish': 'close'})
402  call assert_equal(2, winnr('$'))
403  wincmd p
404  call WaitFor("winnr('$') == 1", waittime)
405  call assert_equal(1, winnr('$'))
406
407  exe 'terminal ++open ' . cmd
408  close!
409  call WaitFor("winnr('$') == 2", waittime)
410  call assert_equal(2, winnr('$'))
411  bwipe
412
413  call term_start(cmd, {'term_finish': 'open'})
414  close!
415  call WaitFor("winnr('$') == 2", waittime)
416  call assert_equal(2, winnr('$'))
417  bwipe
418
419  exe 'terminal ++hidden ++open ' . cmd
420  call assert_equal(1, winnr('$'))
421  call WaitFor("winnr('$') == 2", waittime)
422  call assert_equal(2, winnr('$'))
423  bwipe
424
425  call term_start(cmd, {'term_finish': 'open', 'hidden': 1})
426  call assert_equal(1, winnr('$'))
427  call WaitFor("winnr('$') == 2", waittime)
428  call assert_equal(2, winnr('$'))
429  bwipe
430
431  call assert_fails("call term_start(cmd, {'term_opencmd': 'open'})", 'E475:')
432  call assert_fails("call term_start(cmd, {'term_opencmd': 'split %x'})", 'E475:')
433  call assert_fails("call term_start(cmd, {'term_opencmd': 'split %d and %s'})", 'E475:')
434  call assert_fails("call term_start(cmd, {'term_opencmd': 'split % and %d'})", 'E475:')
435
436  call term_start(cmd, {'term_finish': 'open', 'term_opencmd': '4split | buffer %d'})
437  close!
438  call WaitFor("winnr('$') == 2", waittime)
439  call assert_equal(2, winnr('$'))
440  call assert_equal(4, winheight(0))
441  bwipe
442endfunc
443
444func Test_terminal_cwd()
445  if !executable('pwd')
446    return
447  endif
448  call mkdir('Xdir')
449  let buf = term_start('pwd', {'cwd': 'Xdir'})
450  call WaitFor('"Xdir" == fnamemodify(getline(1), ":t")')
451  call assert_equal('Xdir', fnamemodify(getline(1), ":t"))
452
453  exe buf . 'bwipe'
454  call delete('Xdir', 'rf')
455endfunc
456
457func Test_terminal_servername()
458  if !has('clientserver')
459    return
460  endif
461  let buf = Run_shell_in_terminal({})
462  " Wait for the shell to display a prompt
463  call WaitFor({-> term_getline(buf, 1) != ""})
464  if has('win32')
465    call term_sendkeys(buf, "echo %VIM_SERVERNAME%\r")
466  else
467    call term_sendkeys(buf, "echo $VIM_SERVERNAME\r")
468  endif
469  call term_wait(buf)
470  call Stop_shell_in_terminal(buf)
471  call WaitFor('getline(2) == v:servername')
472  call assert_equal(v:servername, getline(2))
473
474  exe buf . 'bwipe'
475  unlet buf
476endfunc
477
478func Test_terminal_env()
479  let buf = Run_shell_in_terminal({'env': {'TESTENV': 'correct'}})
480  " Wait for the shell to display a prompt
481  call WaitFor({-> term_getline(buf, 1) != ""})
482  if has('win32')
483    call term_sendkeys(buf, "echo %TESTENV%\r")
484  else
485    call term_sendkeys(buf, "echo $TESTENV\r")
486  endif
487  call term_wait(buf)
488  call Stop_shell_in_terminal(buf)
489  call WaitFor('getline(2) == "correct"')
490  call assert_equal('correct', getline(2))
491
492  exe buf . 'bwipe'
493endfunc
494
495" must be last, we can't go back from GUI to terminal
496func Test_zz_terminal_in_gui()
497  if !CanRunGui()
498    return
499  endif
500
501  " Ignore the "failed to create input context" error.
502  call test_ignore_error('E285:')
503
504  gui -f
505
506  call assert_equal(1, winnr('$'))
507  let buf = Run_shell_in_terminal({'term_finish': 'close'})
508  call Stop_shell_in_terminal(buf)
509  call term_wait(buf)
510
511  " closing window wipes out the terminal buffer a with finished job
512  call WaitFor("winnr('$') == 1")
513  call assert_equal(1, winnr('$'))
514  call assert_equal("", bufname(buf))
515
516  unlet g:job
517endfunc
518
519func Test_terminal_list_args()
520  let buf = term_start([&shell, &shellcmdflag, 'echo "123"'])
521  call assert_fails(buf . 'bwipe', 'E517')
522  exe buf . 'bwipe!'
523  call assert_equal("", bufname(buf))
524endfunction
525
526func Test_terminal_noblock()
527  let buf = term_start(&shell)
528  if has('mac')
529    " The shell or something else has a problem dealing with more than 1000
530    " characters at the same time.
531    let len = 1000
532  else
533    let len = 5000
534  endif
535
536  for c in ['a','b','c','d','e','f','g','h','i','j','k']
537    call term_sendkeys(buf, 'echo ' . repeat(c, len) . "\<cr>")
538  endfor
539  call term_sendkeys(buf, "echo done\<cr>")
540
541  " On MS-Windows there is an extra empty line below "done".  Find "done" in
542  " the last-but-one or the last-but-two line.
543  let lnum = term_getsize(buf)[0] - 1
544  call WaitFor({-> term_getline(buf, lnum) =~ "done" || term_getline(buf, lnum - 1) =~ "done"}, 10000)
545  let line = term_getline(buf, lnum)
546  if line !~ 'done'
547    let line = term_getline(buf, lnum - 1)
548  endif
549  call assert_match('done', line)
550
551  let g:job = term_getjob(buf)
552  call Stop_shell_in_terminal(buf)
553  call term_wait(buf)
554  unlet g:job
555  bwipe
556endfunc
557
558func Test_terminal_write_stdin()
559  if !executable('wc')
560    throw 'skipped: wc command not available'
561  endif
562  new
563  call setline(1, ['one', 'two', 'three'])
564  %term wc
565  call WaitFor('getline("$") =~ "3"')
566  let nrs = split(getline('$'))
567  call assert_equal(['3', '3', '14'], nrs)
568  bwipe
569
570  new
571  call setline(1, ['one', 'two', 'three', 'four'])
572  2,3term wc
573  call WaitFor('getline("$") =~ "2"')
574  let nrs = split(getline('$'))
575  call assert_equal(['2', '2', '10'], nrs)
576  bwipe
577
578  if executable('python')
579    new
580    call setline(1, ['print("hello")'])
581    1term ++eof=exit() python
582    " MS-Windows echoes the input, Unix doesn't.
583    call WaitFor('getline("$") =~ "exit" || getline(1) =~ "hello"')
584    if getline(1) =~ 'hello'
585      call assert_equal('hello', getline(1))
586    else
587      call assert_equal('hello', getline(line('$') - 1))
588    endif
589    bwipe
590
591    if has('win32')
592      new
593      call setline(1, ['print("hello")'])
594      1term ++eof=<C-Z> python
595      call WaitFor('getline("$") =~ "Z"')
596      call assert_equal('hello', getline(line('$') - 1))
597      bwipe
598    endif
599  endif
600
601  bwipe!
602endfunc
603
604func Test_terminal_no_cmd()
605  " Todo: make this work in the GUI
606  if !has('gui_running')
607    return
608  endif
609  let buf = term_start('NONE', {})
610  call assert_notequal(0, buf)
611
612  let pty = job_info(term_getjob(buf))['tty_out']
613  call assert_notequal('', pty)
614  if has('win32')
615    silent exe '!start cmd /c "echo look here > ' . pty . '"'
616  else
617    call system('echo "look here" > ' . pty)
618  endif
619  call WaitFor({-> term_getline(buf, 1) =~ "look here"})
620
621  call assert_match('look here', term_getline(buf, 1))
622  bwipe!
623endfunc
624
625func Test_terminal_special_chars()
626  " this file name only works on Unix
627  if !has('unix')
628    return
629  endif
630  call mkdir('Xdir with spaces')
631  call writefile(['x'], 'Xdir with spaces/quoted"file')
632  term ls Xdir\ with\ spaces/quoted\"file
633  call WaitFor('term_getline("", 1) =~ "quoted"')
634  call assert_match('quoted"file', term_getline('', 1))
635  call term_wait('')
636
637  call delete('Xdir with spaces', 'rf')
638  bwipe
639endfunc
640
641func Test_terminal_wrong_options()
642  call assert_fails('call term_start(&shell, {
643	\ "in_io": "file",
644	\ "in_name": "xxx",
645	\ "out_io": "file",
646	\ "out_name": "xxx",
647	\ "err_io": "file",
648	\ "err_name": "xxx"
649	\ })', 'E474:')
650  call assert_fails('call term_start(&shell, {
651	\ "out_buf": bufnr("%")
652	\ })', 'E474:')
653  call assert_fails('call term_start(&shell, {
654	\ "err_buf": bufnr("%")
655	\ })', 'E474:')
656endfunc
657
658func Test_terminal_redir_file()
659  " TODO: this should work on MS-Window
660  if has('unix')
661    let cmd = Get_cat_123_cmd()
662    let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'})
663    call term_wait(buf)
664    call WaitFor('len(readfile("Xfile")) > 0')
665    call assert_match('123', readfile('Xfile')[0])
666    let g:job = term_getjob(buf)
667    call WaitFor('job_status(g:job) == "dead"')
668    call delete('Xfile')
669    bwipe
670  endif
671
672  if has('unix')
673    call writefile(['one line'], 'Xfile')
674    let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
675    call term_wait(buf)
676    call WaitFor('term_getline(' . buf . ', 1) == "one line"')
677    call assert_equal('one line', term_getline(buf, 1))
678    let g:job = term_getjob(buf)
679    call WaitFor('job_status(g:job) == "dead"')
680    bwipe
681    call delete('Xfile')
682  endif
683endfunc
684
685func TerminalTmap(remap)
686  let buf = Run_shell_in_terminal({})
687  call assert_equal('t', mode())
688
689  if a:remap
690    tmap 123 456
691  else
692    tnoremap 123 456
693  endif
694  " don't use abcde, it's an existing command
695  tmap 456 abxde
696  call assert_equal('456', maparg('123', 't'))
697  call assert_equal('abxde', maparg('456', 't'))
698  call feedkeys("123", 'tx')
699  call WaitFor({-> term_getline(buf, term_getcursor(buf)[0]) =~ 'abxde\|456'})
700  let lnum = term_getcursor(buf)[0]
701  if a:remap
702    call assert_match('abxde', term_getline(buf, lnum))
703  else
704    call assert_match('456', term_getline(buf, lnum))
705  endif
706
707  call term_sendkeys(buf, "\r")
708  call Stop_shell_in_terminal(buf)
709  call term_wait(buf)
710
711  tunmap 123
712  tunmap 456
713  call assert_equal('', maparg('123', 't'))
714  close
715  unlet g:job
716endfunc
717
718func Test_terminal_tmap()
719  call TerminalTmap(1)
720  call TerminalTmap(0)
721endfunc
722
723func Test_terminal_wall()
724  let buf = Run_shell_in_terminal({})
725  wall
726  call Stop_shell_in_terminal(buf)
727  call term_wait(buf)
728  exe buf . 'bwipe'
729  unlet g:job
730endfunc
731
732func Test_terminal_wqall()
733  let buf = Run_shell_in_terminal({})
734  call assert_fails('wqall', 'E948')
735  call Stop_shell_in_terminal(buf)
736  call term_wait(buf)
737  exe buf . 'bwipe'
738  unlet g:job
739endfunc
740
741func Test_terminal_composing_unicode()
742  let save_enc = &encoding
743  set encoding=utf-8
744
745  if has('win32')
746    let cmd = "cmd /K chcp 65001"
747    let lnum = [3, 6, 9]
748  else
749    let cmd = &shell
750    let lnum = [1, 3, 5]
751  endif
752
753  enew
754  let buf = term_start(cmd, {'curwin': bufnr('')})
755  let g:job = term_getjob(buf)
756  call term_wait(buf, 50)
757
758  " ascii + composing
759  let txt = "a\u0308bc"
760  call term_sendkeys(buf, "echo " . txt . "\r")
761  call term_wait(buf, 50)
762  call assert_match("echo " . txt, term_getline(buf, lnum[0]))
763  call assert_equal(txt, term_getline(buf, lnum[0] + 1))
764  let l = term_scrape(buf, lnum[0] + 1)
765  call assert_equal("a\u0308", l[0].chars)
766  call assert_equal("b", l[1].chars)
767  call assert_equal("c", l[2].chars)
768
769  " multibyte + composing
770  let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099"
771  call term_sendkeys(buf, "echo " . txt . "\r")
772  call term_wait(buf, 50)
773  call assert_match("echo " . txt, term_getline(buf, lnum[1]))
774  call assert_equal(txt, term_getline(buf, lnum[1] + 1))
775  let l = term_scrape(buf, lnum[1] + 1)
776  call assert_equal("\u304b\u3099", l[0].chars)
777  call assert_equal("\u304e", l[1].chars)
778  call assert_equal("\u304f\u3099", l[2].chars)
779  call assert_equal("\u3052", l[3].chars)
780  call assert_equal("\u3053\u3099", l[4].chars)
781
782  " \u00a0 + composing
783  let txt = "abc\u00a0\u0308"
784  call term_sendkeys(buf, "echo " . txt . "\r")
785  call term_wait(buf, 50)
786  call assert_match("echo " . txt, term_getline(buf, lnum[2]))
787  call assert_equal(txt, term_getline(buf, lnum[2] + 1))
788  let l = term_scrape(buf, lnum[2] + 1)
789  call assert_equal("\u00a0\u0308", l[3].chars)
790
791  call term_sendkeys(buf, "exit\r")
792  call WaitFor('job_status(g:job) == "dead"')
793  call assert_equal('dead', job_status(g:job))
794  bwipe!
795  unlet g:job
796  let &encoding = save_enc
797endfunc
798
799func Test_terminal_aucmd_on_close()
800  fun Nop()
801    let s:called = 1
802  endfun
803
804  aug repro
805      au!
806      au BufWinLeave * call Nop()
807  aug END
808
809  let [cmd, waittime] = s:get_sleep_cmd()
810
811  call assert_equal(1, winnr('$'))
812  new
813  call setline(1, ['one', 'two'])
814  exe 'term ++close ' . cmd
815  wincmd p
816  call WaitFor("winnr('$') == 2", waittime)
817  call assert_equal(1, s:called)
818  bwipe!
819
820  unlet s:called
821  au! repro
822  delfunc Nop
823endfunc
824
825func Test_terminal_term_start_empty_command()
826  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
827  call assert_fails(cmd, 'E474')
828  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
829  call assert_fails(cmd, 'E474')
830  let cmd = "call term_start({}, {'curwin' : 1, 'term_finish' : 'close'})"
831  call assert_fails(cmd, 'E474')
832  let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})"
833  call assert_fails(cmd, 'E474')
834endfunc
835
836func Test_terminal_response_to_control_sequence()
837  if !has('unix')
838    return
839  endif
840
841  let buf = Run_shell_in_terminal({})
842  call WaitFor({-> term_getline(buf, 1) != ''})
843
844  call term_sendkeys(buf, "cat\<CR>")
845  call WaitFor({-> term_getline(buf, 1) =~ 'cat'})
846
847  " Request the cursor position.
848  call term_sendkeys(buf, "\x1b[6n\<CR>")
849
850  " Wait for output from tty to display, below an empty line.
851  call WaitFor({-> term_getline(buf, 4) =~ '3;1R'})
852
853  " End "cat" gently.
854  call term_sendkeys(buf, "\<CR>\<C-D>")
855
856  call Stop_shell_in_terminal(buf)
857  exe buf . 'bwipe'
858  unlet g:job
859endfunc
860
861" Run Vim, start a terminal in that Vim with the kill argument,
862" :qall works.
863func Run_terminal_qall_kill(line1, line2)
864  " 1. Open a terminal window and wait for the prompt to appear
865  " 2. set kill using term_setkill()
866  " 3. make Vim exit, it will kill the shell
867  let after = [
868	\ a:line1,
869	\ 'let buf = bufnr("%")',
870	\ 'while term_getline(buf, 1) =~ "^\\s*$"',
871	\ '  sleep 10m',
872	\ 'endwhile',
873	\ a:line2,
874	\ 'au VimLeavePre * call writefile(["done"], "Xdone")',
875	\ 'qall',
876	\ ]
877  if !RunVim([], after, '')
878    return
879  endif
880  call assert_equal("done", readfile("Xdone")[0])
881  call delete("Xdone")
882endfunc
883
884" Run Vim in a terminal, then start a terminal in that Vim with a kill
885" argument, check that :qall works.
886func Test_terminal_qall_kill_arg()
887  call Run_terminal_qall_kill('term ++kill=kill', '')
888endfunc
889
890" Run Vim, start a terminal in that Vim, set the kill argument with
891" term_setkill(), check that :qall works.
892func Test_terminal_qall_kill_func()
893  call Run_terminal_qall_kill('term', 'call term_setkill(buf, "kill")')
894endfunc
895
896" Run Vim, start a terminal in that Vim without the kill argument,
897" check that :qall does not exit, :qall! does.
898func Test_terminal_qall_exit()
899  let after = [
900	\ 'term',
901	\ 'let buf = bufnr("%")',
902	\ 'while term_getline(buf, 1) =~ "^\\s*$"',
903	\ '  sleep 10m',
904	\ 'endwhile',
905	\ 'set nomore',
906	\ 'au VimLeavePre * call writefile(["too early"], "Xdone")',
907	\ 'qall',
908	\ 'au! VimLeavePre * exe buf . "bwipe!" | call writefile(["done"], "Xdone")',
909	\ 'cquit',
910	\ ]
911  if !RunVim([], after, '')
912    return
913  endif
914  call assert_equal("done", readfile("Xdone")[0])
915  call delete("Xdone")
916endfunc
917
918" Run Vim in a terminal, then start a terminal in that Vim without a kill
919" argument, check that :confirm qall works.
920func Test_terminal_qall_prompt()
921  if !CanRunVimInTerminal()
922    return
923  endif
924  let buf = RunVimInTerminal('', {})
925
926  " Open a terminal window and wait for the prompt to appear
927  call term_sendkeys(buf, ":term\<CR>")
928  call WaitFor({-> term_getline(buf, 10) =~ '\[running]'})
929  call WaitFor({-> term_getline(buf, 1) !~ '^\s*$'})
930
931  " make Vim exit, it will prompt to kill the shell
932  call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>")
933  call WaitFor({-> term_getline(buf, 20) =~ 'ancel:'})
934  call term_sendkeys(buf, "y")
935  call WaitFor({-> term_getstatus(buf) == "finished"})
936
937  " close the terminal window where Vim was running
938  quit
939endfunc
940
941func Test_terminal_open_autocmd()
942  augroup repro
943    au!
944    au TerminalOpen * let s:called += 1
945  augroup END
946
947  let s:called = 0
948
949  " Open a terminal window with :terminal
950  terminal
951  call assert_equal(1, s:called)
952  bwipe!
953
954  " Open a terminal window with term_start()
955  call term_start(&shell)
956  call assert_equal(2, s:called)
957  bwipe!
958
959  " Open a hidden terminal buffer with :terminal
960  terminal ++hidden
961  call assert_equal(3, s:called)
962  for buf in term_list()
963    exe buf . "bwipe!"
964  endfor
965
966  " Open a hidden terminal buffer with term_start()
967  let buf = term_start(&shell, {'hidden': 1})
968  call assert_equal(4, s:called)
969  exe buf . "bwipe!"
970
971  unlet s:called
972  au! repro
973endfunction
974
975func Check_dump01(off)
976  call assert_equal('one two three four five', trim(getline(a:off + 1)))
977  call assert_equal('~           Select Word', trim(getline(a:off + 7)))
978  call assert_equal(':popup PopUp', trim(getline(a:off + 20)))
979endfunc
980
981func Test_terminal_dumpwrite_composing()
982  if !CanRunVimInTerminal()
983    return
984  endif
985  let save_enc = &encoding
986  set encoding=utf-8
987  call assert_equal(1, winnr('$'))
988
989  let text = " a\u0300 e\u0302 o\u0308"
990  call writefile([text], 'Xcomposing')
991  let buf = RunVimInTerminal('Xcomposing', {})
992  call WaitFor({-> term_getline(buf, 1) =~ text})
993  call term_dumpwrite(buf, 'Xdump')
994  let dumpline = readfile('Xdump')[0]
995  call assert_match('|à| |ê| |ö', dumpline)
996
997  call StopVimInTerminal(buf)
998  call delete('Xcomposing')
999  call delete('Xdump')
1000  let &encoding = save_enc
1001endfunc
1002
1003" just testing basic functionality.
1004func Test_terminal_dumpload()
1005  call assert_equal(1, winnr('$'))
1006  call term_dumpload('dumps/Test_popup_command_01.dump')
1007  call assert_equal(2, winnr('$'))
1008  call assert_equal(20, line('$'))
1009  call Check_dump01(0)
1010  quit
1011endfunc
1012
1013func Test_terminal_dumpdiff()
1014  call assert_equal(1, winnr('$'))
1015  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump')
1016  call assert_equal(2, winnr('$'))
1017  call assert_equal(62, line('$'))
1018  call Check_dump01(0)
1019  call Check_dump01(42)
1020  call assert_equal('           bbbbbbbbbbbbbbbbbb ', getline(26)[0:29])
1021  quit
1022endfunc
1023
1024func Test_terminal_dumpdiff_options()
1025  set laststatus=0
1026  call assert_equal(1, winnr('$'))
1027  let height = winheight(0)
1028  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 1, 'term_cols': 33})
1029  call assert_equal(2, winnr('$'))
1030  call assert_equal(height, winheight(winnr()))
1031  call assert_equal(33, winwidth(winnr()))
1032  call assert_equal('dump diff dumps/Test_popup_command_01.dump', bufname('%'))
1033  quit
1034
1035  call assert_equal(1, winnr('$'))
1036  let width = winwidth(0)
1037  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 0, 'term_rows': 13, 'term_name': 'something else'})
1038  call assert_equal(2, winnr('$'))
1039  call assert_equal(width, winwidth(winnr()))
1040  call assert_equal(13, winheight(winnr()))
1041  call assert_equal('something else', bufname('%'))
1042  quit
1043
1044  call assert_equal(1, winnr('$'))
1045  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1})
1046  call assert_equal(1, winnr('$'))
1047  bwipe
1048
1049  set laststatus&
1050endfunc
1051
1052func Api_drop_common(options)
1053  call assert_equal(1, winnr('$'))
1054
1055  " Use the title termcap entries to output the escape sequence.
1056  call writefile([
1057	\ 'set title',
1058	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1059	\ 'let &titlestring = ''["drop","Xtextfile"' . a:options . ']''',
1060	\ 'redraw',
1061	\ "set t_ts=",
1062	\ ], 'Xscript')
1063  let buf = RunVimInTerminal('-S Xscript', {})
1064  call WaitFor({-> bufnr('Xtextfile') > 0})
1065  call assert_equal('Xtextfile', expand('%:t'))
1066  call assert_true(winnr('$') >= 3)
1067  return buf
1068endfunc
1069
1070func Test_terminal_api_drop_newwin()
1071  if !CanRunVimInTerminal()
1072    return
1073  endif
1074  let buf = Api_drop_common('')
1075  call assert_equal(0, &bin)
1076  call assert_equal('', &fenc)
1077
1078  call StopVimInTerminal(buf)
1079  call delete('Xscript')
1080  bwipe Xtextfile
1081endfunc
1082
1083func Test_terminal_api_drop_newwin_bin()
1084  if !CanRunVimInTerminal()
1085    return
1086  endif
1087  let buf = Api_drop_common(',{"bin":1}')
1088  call assert_equal(1, &bin)
1089
1090  call StopVimInTerminal(buf)
1091  call delete('Xscript')
1092  bwipe Xtextfile
1093endfunc
1094
1095func Test_terminal_api_drop_newwin_binary()
1096  if !CanRunVimInTerminal()
1097    return
1098  endif
1099  let buf = Api_drop_common(',{"binary":1}')
1100  call assert_equal(1, &bin)
1101
1102  call StopVimInTerminal(buf)
1103  call delete('Xscript')
1104  bwipe Xtextfile
1105endfunc
1106
1107func Test_terminal_api_drop_newwin_nobin()
1108  if !CanRunVimInTerminal()
1109    return
1110  endif
1111  set binary
1112  let buf = Api_drop_common(',{"nobin":1}')
1113  call assert_equal(0, &bin)
1114
1115  call StopVimInTerminal(buf)
1116  call delete('Xscript')
1117  bwipe Xtextfile
1118  set nobinary
1119endfunc
1120
1121func Test_terminal_api_drop_newwin_nobinary()
1122  if !CanRunVimInTerminal()
1123    return
1124  endif
1125  set binary
1126  let buf = Api_drop_common(',{"nobinary":1}')
1127  call assert_equal(0, &bin)
1128
1129  call StopVimInTerminal(buf)
1130  call delete('Xscript')
1131  bwipe Xtextfile
1132  set nobinary
1133endfunc
1134
1135func Test_terminal_api_drop_newwin_ff()
1136  if !CanRunVimInTerminal()
1137    return
1138  endif
1139  let buf = Api_drop_common(',{"ff":"dos"}')
1140  call assert_equal("dos", &ff)
1141
1142  call StopVimInTerminal(buf)
1143  call delete('Xscript')
1144  bwipe Xtextfile
1145endfunc
1146
1147func Test_terminal_api_drop_newwin_fileformat()
1148  if !CanRunVimInTerminal()
1149    return
1150  endif
1151  let buf = Api_drop_common(',{"fileformat":"dos"}')
1152  call assert_equal("dos", &ff)
1153
1154  call StopVimInTerminal(buf)
1155  call delete('Xscript')
1156  bwipe Xtextfile
1157endfunc
1158
1159func Test_terminal_api_drop_newwin_enc()
1160  if !CanRunVimInTerminal()
1161    return
1162  endif
1163  let buf = Api_drop_common(',{"enc":"utf-16"}')
1164  call assert_equal("utf-16", &fenc)
1165
1166  call StopVimInTerminal(buf)
1167  call delete('Xscript')
1168  bwipe Xtextfile
1169endfunc
1170
1171func Test_terminal_api_drop_newwin_encoding()
1172  if !CanRunVimInTerminal()
1173    return
1174  endif
1175  let buf = Api_drop_common(',{"encoding":"utf-16"}')
1176  call assert_equal("utf-16", &fenc)
1177
1178  call StopVimInTerminal(buf)
1179  call delete('Xscript')
1180  bwipe Xtextfile
1181endfunc
1182
1183func Test_terminal_api_drop_oldwin()
1184  if !CanRunVimInTerminal()
1185    return
1186  endif
1187  let firstwinid = win_getid()
1188  split Xtextfile
1189  let textfile_winid = win_getid()
1190  call assert_equal(2, winnr('$'))
1191  call win_gotoid(firstwinid)
1192
1193  " Use the title termcap entries to output the escape sequence.
1194  call writefile([
1195	\ 'set title',
1196	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1197	\ 'let &titlestring = ''["drop","Xtextfile"]''',
1198	\ 'redraw',
1199	\ "set t_ts=",
1200	\ ], 'Xscript')
1201  let buf = RunVimInTerminal('-S Xscript', {'rows': 10})
1202  call WaitFor({-> expand('%:t') =='Xtextfile'})
1203  call assert_equal(textfile_winid, win_getid())
1204
1205  call StopVimInTerminal(buf)
1206  call delete('Xscript')
1207  bwipe Xtextfile
1208endfunc
1209
1210func Tapi_TryThis(bufnum, arg)
1211  let g:called_bufnum = a:bufnum
1212  let g:called_arg = a:arg
1213endfunc
1214
1215func WriteApiCall(funcname)
1216  " Use the title termcap entries to output the escape sequence.
1217  call writefile([
1218	\ 'set title',
1219	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1220	\ 'let &titlestring = ''["call","' . a:funcname . '",["hello",123]]''',
1221	\ 'redraw',
1222	\ "set t_ts=",
1223	\ ], 'Xscript')
1224endfunc
1225
1226func Test_terminal_api_call()
1227  if !CanRunVimInTerminal()
1228    return
1229  endif
1230
1231  call WriteApiCall('Tapi_TryThis')
1232  let buf = RunVimInTerminal('-S Xscript', {})
1233  call WaitFor({-> exists('g:called_bufnum')})
1234  call assert_equal(buf, g:called_bufnum)
1235  call assert_equal(['hello', 123], g:called_arg)
1236
1237  call StopVimInTerminal(buf)
1238  call delete('Xscript')
1239  unlet g:called_bufnum
1240  unlet g:called_arg
1241endfunc
1242
1243func Test_terminal_api_call_fails()
1244  if !CanRunVimInTerminal()
1245    return
1246  endif
1247
1248  call WriteApiCall('TryThis')
1249  call ch_logfile('Xlog', 'w')
1250  let buf = RunVimInTerminal('-S Xscript', {})
1251  call WaitFor({-> string(readfile('Xlog')) =~ 'Invalid function name: TryThis'})
1252
1253  call StopVimInTerminal(buf)
1254  call delete('Xscript')
1255  call ch_logfile('', '')
1256  call delete('Xlog')
1257endfunc
1258