diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 08:50:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 08:50:31 +0000 |
commit | aed8ce9da277f5ecffe968b324f242c41c3b752a (patch) | |
tree | d2e538394cb7a8a7c42a4aac6ccf1a8e3256999b /src/testdir/test_terminal.vim | |
parent | Initial commit. (diff) | |
download | vim-aed8ce9da277f5ecffe968b324f242c41c3b752a.tar.xz vim-aed8ce9da277f5ecffe968b324f242c41c3b752a.zip |
Adding upstream version 2:9.0.1378.upstream/2%9.0.1378upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/testdir/test_terminal.vim')
-rw-r--r-- | src/testdir/test_terminal.vim | 2353 |
1 files changed, 2353 insertions, 0 deletions
diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim new file mode 100644 index 0000000..b0c29ec --- /dev/null +++ b/src/testdir/test_terminal.vim @@ -0,0 +1,2353 @@ +" Tests for the terminal window. +" This is split in two, because it can take a lot of time. +" See test_terminal2.vim and test_terminal3.vim for further tests. + +source check.vim +CheckFeature terminal + +source shared.vim +source screendump.vim +source mouse.vim +source term_util.vim + +let s:python = PythonProg() +let $PROMPT_COMMAND='' + +func Test_terminal_basic() + call test_override('vterm_title', 1) + au TerminalOpen * let b:done = 'yes' + let buf = Run_shell_in_terminal({}) + + call assert_equal('t', mode()) + call assert_equal('yes', b:done) + call assert_match('%aR[^\n]*running]', execute('ls')) + call assert_match('%aR[^\n]*running]', execute('ls R')) + call assert_notmatch('%[^\n]*running]', execute('ls F')) + call assert_notmatch('%[^\n]*running]', execute('ls ?')) + call assert_fails('set modifiable', 'E946:') + + call StopShellInTerminal(buf) + call assert_equal('n', mode()) + call assert_match('%aF[^\n]*finished]', execute('ls')) + call assert_match('%aF[^\n]*finished]', execute('ls F')) + call assert_notmatch('%[^\n]*finished]', execute('ls R')) + call assert_notmatch('%[^\n]*finished]', execute('ls ?')) + + " closing window wipes out the terminal buffer a with finished job + close + call assert_equal("", bufname(buf)) + + au! TerminalOpen + call test_override('ALL', 0) + unlet g:job +endfunc + +func Test_terminal_no_name() + let buf = Run_shell_in_terminal({}) + call assert_match('^!', bufname(buf)) + 0file + call assert_equal("", bufname(buf)) + call assert_match('\[No Name\]', execute('file')) + call StopShellInTerminal(buf) +endfunc + +func Test_terminal_TerminalWinOpen() + au TerminalWinOpen * let b:done = 'yes' + let buf = Run_shell_in_terminal({}) + call assert_equal('yes', b:done) + call StopShellInTerminal(buf) + " closing window wipes out the terminal buffer with the finished job + close + + if has("unix") + terminal ++hidden ++open sleep 1 + sleep 1 + call assert_fails("echo b:done", 'E121:') + endif + + au! TerminalWinOpen +endfunc + +func Test_terminal_make_change() + let buf = Run_shell_in_terminal({}) + call StopShellInTerminal(buf) + + setlocal modifiable + exe "normal Axxx\<Esc>" + call assert_fails(buf . 'bwipe', 'E89:') + undo + + exe buf . 'bwipe' + unlet g:job +endfunc + +func Test_terminal_paste_register() + let @" = "text to paste" + + let buf = Run_shell_in_terminal({}) + " Wait for the shell to display a prompt + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + + call feedkeys("echo \<C-W>\"\" \<C-W>\"=37 + 5\<CR>\<CR>", 'xt') + call WaitForAssert({-> assert_match("echo text to paste 42$", getline(1))}) + call WaitForAssert({-> assert_equal('text to paste 42', 2->getline())}) + + exe buf . 'bwipe!' + unlet g:job +endfunc + +func Test_terminal_unload_buffer() + let buf = Run_shell_in_terminal({}) + call assert_fails(buf . 'bunload', 'E948:') + exe buf . 'bunload!' + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf)) + + unlet g:job +endfunc + +func Test_terminal_wipe_buffer() + let buf = Run_shell_in_terminal({}) + call assert_fails(buf . 'bwipe', 'E948:') + exe buf . 'bwipe!' + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf)) + + unlet g:job +endfunc + +" Test that using ':confirm bwipe' on terminal works +func Test_terminal_confirm_wipe_buffer() + CheckUnix + CheckNotGui + CheckFeature dialog_con + let buf = Run_shell_in_terminal({}) + call assert_fails(buf . 'bwipe', 'E948:') + call feedkeys('n', 'L') + call assert_fails('confirm ' .. buf .. 'bwipe', 'E517:') + call assert_equal(buf, bufnr()) + call assert_equal(1, &modified) + call feedkeys('y', 'L') + exe 'confirm ' .. buf .. 'bwipe' + call assert_notequal(buf, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf)) + + unlet g:job +endfunc + +" Test that using :b! will hide the terminal +func Test_terminal_goto_buffer() + let buf_mod = bufnr() + let buf_term = Run_shell_in_terminal({}) + call assert_equal(buf_term, bufnr()) + call assert_fails(buf_mod . 'b', 'E948:') + exe buf_mod . 'b!' + call assert_equal(buf_mod, bufnr()) + call assert_equal('run', job_status(g:job)) + call assert_notequal('', bufname(buf_term)) + exec buf_mod .. 'bwipe!' + exec buf_term .. 'bwipe!' + + unlet g:job +endfunc + +" Test that using ':confirm :b' will kill terminal +func Test_terminal_confirm_goto_buffer() + CheckUnix + CheckNotGui + CheckFeature dialog_con + let buf_mod = bufnr() + let buf_term = Run_shell_in_terminal({}) + call feedkeys('n', 'L') + exe 'confirm ' .. buf_mod .. 'b' + call assert_equal(buf_term, bufnr()) + call feedkeys('y', 'L') + exec 'confirm ' .. buf_mod .. 'b' + call assert_equal(buf_mod, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf_term)) + exec buf_mod .. 'bwipe!' + + unlet g:job +endfunc + +" Test that using :close! will hide the terminal +func Test_terminal_close_win() + let buf = Run_shell_in_terminal({}) + call assert_equal(buf, bufnr()) + call assert_fails('close', 'E948:') + close! + call assert_notequal(buf, bufnr()) + call assert_equal('run', job_status(g:job)) + call assert_notequal('', bufname(buf)) + exec buf .. 'bwipe!' + + unlet g:job +endfunc + +" Test that using ':confirm close' will kill terminal +func Test_terminal_confirm_close_win() + CheckUnix + CheckNotGui + CheckFeature dialog_con + let buf = Run_shell_in_terminal({}) + call feedkeys('n', 'L') + confirm close + call assert_equal(buf, bufnr()) + call feedkeys('y', 'L') + confirm close + call assert_notequal(buf, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf)) + + unlet g:job +endfunc + +" Test that using :quit! will kill the terminal +func Test_terminal_quit() + let buf = Run_shell_in_terminal({}) + call assert_equal(buf, bufnr()) + call assert_fails('quit', 'E948:') + quit! + call assert_notequal(buf, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + call assert_equal("", bufname(buf)) + + unlet g:job +endfunc + +" Test that using ':confirm quit' will kill terminal +func Test_terminal_confirm_quit() + CheckUnix + CheckNotGui + CheckFeature dialog_con + let buf = Run_shell_in_terminal({}) + call feedkeys('n', 'L') + confirm quit + call assert_equal(buf, bufnr()) + call feedkeys('y', 'L') + confirm quit + call assert_notequal(buf, bufnr()) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + + unlet g:job +endfunc + +" Test :q or :next + +func Test_terminal_split_quit() + let buf = Run_shell_in_terminal({}) + split + quit! + call TermWait(buf) + sleep 50m + call assert_equal('run', job_status(g:job)) + + quit! + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + + call assert_equal("", bufname(buf)) + unlet g:job +endfunc + +func Test_terminal_hide_buffer_job_running() + let buf = Run_shell_in_terminal({}) + setlocal bufhidden=hide + quit + for nr in range(1, winnr('$')) + call assert_notequal(winbufnr(nr), buf) + endfor + call assert_true(bufloaded(buf)) + call assert_true(buflisted(buf)) + + exe 'split ' . buf . 'buf' + call StopShellInTerminal(buf) + exe buf . 'bwipe' + + unlet g:job +endfunc + +func Test_terminal_hide_buffer_job_finished() + term echo hello + let buf = bufnr() + call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))}) + + call assert_true(bufloaded(buf)) + call assert_true(buflisted(buf)) + + " Test :hide + hide + call assert_true(bufloaded(buf)) + call assert_true(buflisted(buf)) + split + exe buf .. 'buf' + call assert_equal(buf, bufnr()) + + " Test bufhidden, which exercises a different code path + setlocal bufhidden=hide + edit Xasdfasdf + call assert_true(bufloaded(buf)) + call assert_true(buflisted(buf)) + exe buf .. 'buf' + call assert_equal(buf, bufnr()) + setlocal bufhidden= + + edit Xasdfasdf + call assert_false(bufloaded(buf)) + call assert_false(buflisted(buf)) + bwipe Xasdfasdf +endfunc + +func Test_terminal_rename_buffer() + let cmd = Get_cat_123_cmd() + let buf = term_start(cmd, {'term_name': 'foo'}) + call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))}) + call assert_equal('foo', bufname()) + call assert_match('foo.*finished', execute('ls')) + file bar + call assert_equal('bar', bufname()) + call assert_match('bar.*finished', execute('ls')) + exe 'bwipe! ' .. buf +endfunc + +func s:Nasty_exit_cb(job, st) + exe g:buf . 'bwipe!' + let g:buf = 0 +endfunc + +func Get_cat_123_cmd() + if has('win32') + if !has('conpty') + return 'cmd /c "cls && color 2 && echo 123"' + else + " When clearing twice, extra sequence is not output. + return 'cmd /c "cls && cls && color 2 && echo 123"' + endif + else + call writefile(["\<Esc>[32m123"], 'Xtext') + return "cat Xtext" + endif +endfunc + +func Test_terminal_nasty_cb() + let cmd = Get_cat_123_cmd() + let g:buf = term_start(cmd, {'exit_cb': function('s:Nasty_exit_cb')}) + let g:job = term_getjob(g:buf) + + call WaitForAssert({-> assert_equal("dead", job_status(g:job))}) + call WaitForAssert({-> assert_equal(0, g:buf)}) + unlet g:job + unlet g:buf + call delete('Xtext') +endfunc + +func Check_123(buf) + let l = term_scrape(a:buf, 0) + call assert_true(len(l) == 0) + let l = term_scrape(a:buf, 999) + call assert_true(len(l) == 0) + let l = a:buf->term_scrape(1) + call assert_true(len(l) > 0) + call assert_equal('1', l[0].chars) + call assert_equal('2', l[1].chars) + call assert_equal('3', l[2].chars) + call assert_equal('#00e000', l[0].fg) + call assert_equal(0, term_getattr(l[0].attr, 'bold')) + call assert_equal(0, l[0].attr->term_getattr('italic')) + if has('win32') + " On Windows 'background' always defaults to dark, even though the terminal + " may use a light background. Therefore accept both white and black. + call assert_match('#ffffff\|#000000', l[0].bg) + else + if &background == 'light' + call assert_equal('#ffffff', l[0].bg) + else + call assert_equal('#000000', l[0].bg) + endif + endif + + let l = term_getline(a:buf, -1) + call assert_equal('', l) + let l = term_getline(a:buf, 0) + call assert_equal('', l) + let l = term_getline(a:buf, 999) + call assert_equal('', l) + let l = term_getline(a:buf, 1) + call assert_equal('123', l) +endfunc + +func Test_terminal_scrape_123() + let cmd = Get_cat_123_cmd() + let buf = term_start(cmd) + + let termlist = term_list() + call assert_equal(1, len(termlist)) + call assert_equal(buf, termlist[0]) + + " Nothing happens with invalid buffer number + call term_wait(1234) + + call TermWait(buf) + " On MS-Windows we first get a startup message of two lines, wait for the + " "cls" to happen, after that we have one line with three characters. + call WaitForAssert({-> assert_equal(3, len(term_scrape(buf, 1)))}) + call Check_123(buf) + + " Must still work after the job ended. + let job = term_getjob(buf) + call WaitForAssert({-> assert_equal("dead", job_status(job))}) + call TermWait(buf) + call Check_123(buf) + + exe buf . 'bwipe' + call delete('Xtext') +endfunc + +func Test_terminal_scrape_multibyte() + call writefile(["léttまrs"], 'Xtext', 'D') + if has('win32') + " Run cmd with UTF-8 codepage to make the type command print the expected + " multibyte characters. + let buf = term_start("cmd /K chcp 65001") + call term_sendkeys(buf, "type Xtext\<CR>") + eval buf->term_sendkeys("exit\<CR>") + let line = 4 + else + let buf = term_start("cat Xtext") + let line = 1 + endif + + call WaitFor({-> len(term_scrape(buf, line)) >= 7 && term_scrape(buf, line)[0].chars == "l"}) + let l = term_scrape(buf, line) + call assert_true(len(l) >= 7) + call assert_equal('l', l[0].chars) + call assert_equal('é', l[1].chars) + call assert_equal(1, l[1].width) + call assert_equal('t', l[2].chars) + call assert_equal('t', l[3].chars) + call assert_equal('ま', l[4].chars) + call assert_equal(2, l[4].width) + call assert_equal('r', l[5].chars) + call assert_equal('s', l[6].chars) + + let job = term_getjob(buf) + call WaitForAssert({-> assert_equal("dead", job_status(job))}) + call TermWait(buf) + + exe buf . 'bwipe' +endfunc + +func Test_terminal_one_column() + " This creates a terminal, displays a double-wide character and makes the + " window one column wide. This used to cause a crash. + let width = &columns + botright vert term + let buf = bufnr('$') + call TermWait(buf, 100) + exe "set columns=" .. (width / 2) + redraw + call term_sendkeys(buf, "キ") + call TermWait(buf, 10) + exe "set columns=" .. width + exe buf . 'bwipe!' +endfunc + +func Test_terminal_scroll() + call writefile(range(1, 200), 'Xtext', 'D') + if has('win32') + let cmd = 'cmd /c "type Xtext"' + else + let cmd = "cat Xtext" + endif + let buf = term_start(cmd) + + let job = term_getjob(buf) + call WaitForAssert({-> assert_equal("dead", job_status(job))}) + call TermWait(buf) + + " wait until the scrolling stops + while 1 + let scrolled = buf->term_getscrolled() + sleep 20m + if scrolled == buf->term_getscrolled() + break + endif + endwhile + + call assert_equal('1', getline(1)) + call assert_equal('1', term_getline(buf, 1 - scrolled)) + call assert_equal('49', getline(49)) + call assert_equal('49', term_getline(buf, 49 - scrolled)) + call assert_equal('200', getline(200)) + call assert_equal('200', term_getline(buf, 200 - scrolled)) + + exe buf . 'bwipe' +endfunc + +func Test_terminal_scrollback() + let buf = Run_shell_in_terminal({'term_rows': 15}) + set termwinscroll=100 + call writefile(range(150), 'Xtext', 'D') + if has('win32') + call term_sendkeys(buf, "type Xtext\<CR>") + else + call term_sendkeys(buf, "cat Xtext\<CR>") + endif + let rows = term_getsize(buf)[0] + " On MS-Windows there is an empty line, check both last line and above it. + call WaitForAssert({-> assert_match( '149', term_getline(buf, rows - 1) . term_getline(buf, rows - 2))}) + let lines = line('$') + call assert_inrange(91, 100, lines) + + call StopShellInTerminal(buf) + exe buf . 'bwipe' + set termwinscroll& +endfunc + +func Test_terminal_postponed_scrollback() + " tail -f only works on Unix + CheckUnix + + call writefile(range(50), 'Xtext', 'D') + call writefile([ + \ 'set shell=/bin/sh noruler', + \ 'terminal', + \ 'sleep 200m', + \ 'call feedkeys("tail -n 100 -f Xtext\<CR>", "xt")', + \ 'sleep 100m', + \ 'call feedkeys("\<C-W>N", "xt")', + \ ], 'XTest_postponed', 'D') + let buf = RunVimInTerminal('-S XTest_postponed', {}) + " Check that the Xtext lines are displayed and in Terminal-Normal mode + call VerifyScreenDump(buf, 'Test_terminal_scrollback_1', {}) + + silent !echo 'one more line' >>Xtext + " Screen will not change, move cursor to get a different dump + call term_sendkeys(buf, "k") + call VerifyScreenDump(buf, 'Test_terminal_scrollback_2', {}) + + " Back to Terminal-Job mode, text will scroll and show the extra line. + call term_sendkeys(buf, "a") + call VerifyScreenDump(buf, 'Test_terminal_scrollback_3', {}) + + " stop "tail -f" + call term_sendkeys(buf, "\<C-C>") + call TermWait(buf, 25) + " stop shell + call term_sendkeys(buf, "exit\<CR>") + call TermWait(buf, 50) + " close terminal window + let tsk_ret = term_sendkeys(buf, ":q\<CR>") + + " check type of term_sendkeys() return value + echo type(tsk_ret) + + call StopVimInTerminal(buf) +endfunc + +" Run diff on two dumps with different size. +func Test_terminal_dumpdiff_size() + call assert_equal(1, winnr('$')) + call term_dumpdiff('dumps/Test_incsearch_search_01.dump', 'dumps/Test_popup_command_01.dump') + call assert_equal(2, winnr('$')) + call assert_match('Test_incsearch_search_01.dump', getline(10)) + call assert_match(' +++++$', getline(11)) + call assert_match('Test_popup_command_01.dump', getline(31)) + call assert_equal(repeat('+', 75), getline(30)) + quit +endfunc + +func Test_terminal_size() + let cmd = Get_cat_123_cmd() + + exe 'terminal ++rows=5 ' . cmd + let size = term_getsize('') + bwipe! + call assert_equal(5, size[0]) + + call term_start(cmd, {'term_rows': 6}) + let size = term_getsize('') + bwipe! + call assert_equal(6, size[0]) + + vsplit + exe 'terminal ++rows=5 ++cols=33 ' . cmd + call assert_equal([5, 33], ''->term_getsize()) + + call term_setsize('', 6, 0) + call assert_equal([6, 33], term_getsize('')) + + eval ''->term_setsize(0, 35) + call assert_equal([6, 35], term_getsize('')) + + call term_setsize('', 7, 30) + call assert_equal([7, 30], term_getsize('')) + + bwipe! + call assert_fails("call term_setsize('', 7, 30)", "E955:") + + call term_start(cmd, {'term_rows': 6, 'term_cols': 36}) + let size = term_getsize('') + bwipe! + call assert_equal([6, 36], size) + + exe 'vertical terminal ++cols=20 ' . cmd + let size = term_getsize('') + bwipe! + call assert_equal(20, size[1]) + + eval cmd->term_start({'vertical': 1, 'term_cols': 26}) + let size = term_getsize('') + bwipe! + call assert_equal(26, size[1]) + + split + exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd + let size = term_getsize('') + bwipe! + call assert_equal([6, 20], size) + + call term_start(cmd, {'vertical': 1, 'term_rows': 7, 'term_cols': 27}) + let size = term_getsize('') + bwipe! + call assert_equal([7, 27], size) + + call assert_fails("call term_start(cmd, {'term_rows': -1})", 'E475:') + call assert_fails("call term_start(cmd, {'term_rows': 1001})", 'E475:') + call assert_fails("call term_start(cmd, {'term_rows': 10.0})", 'E805:') + + call delete('Xtext') +endfunc + +func Test_terminal_zero_height() + split + wincmd j + anoremenu 1.1 WinBar.test : + terminal ++curwin + wincmd k + wincmd _ + redraw + + call term_sendkeys(bufnr(), "exit\r") + bwipe! +endfunc + +func Test_terminal_curwin() + let cmd = Get_cat_123_cmd() + call assert_equal(1, winnr('$')) + + split Xdummy + call setline(1, 'dummy') + write + call assert_equal(1, getbufinfo('Xdummy')[0].loaded) + exe 'terminal ++curwin ' . cmd + call assert_equal(2, winnr('$')) + call assert_equal(0, getbufinfo('Xdummy')[0].loaded) + bwipe! + + split Xdummy + call term_start(cmd, {'curwin': 1}) + call assert_equal(2, winnr('$')) + bwipe! + + split Xdummy + call setline(1, 'change') + call assert_fails('terminal ++curwin ' . cmd, 'E37:') + call assert_equal(2, winnr('$')) + exe 'terminal! ++curwin ' . cmd + call assert_equal(2, winnr('$')) + bwipe! + + split Xdummy + call setline(1, 'change') + call assert_fails("call term_start(cmd, {'curwin': 1})", 'E37:') + call assert_equal(2, winnr('$')) + bwipe! + + split Xdummy + bwipe! + call delete('Xtext') + call delete('Xdummy') +endfunc + +func s:get_sleep_cmd() + if s:python != '' + let cmd = s:python . " test_short_sleep.py" + " 500 was not enough for Travis + let waittime = 900 + else + echo 'This will take five seconds...' + let waittime = 2000 + if has('win32') + let cmd = $windir . '\system32\timeout.exe 1' + else + let cmd = 'sleep 1' + endif + endif + return [cmd, waittime] +endfunc + +func Test_terminal_finish_open_close() + call assert_equal(1, winnr('$')) + + let [cmd, waittime] = s:get_sleep_cmd() + + " shell terminal closes automatically + terminal + let buf = bufnr('%') + call assert_equal(2, winnr('$')) + " Wait for the shell to display a prompt + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + call StopShellInTerminal(buf) + call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime) + + " shell terminal that does not close automatically + terminal ++noclose + let buf = bufnr('%') + call assert_equal(2, winnr('$')) + " Wait for the shell to display a prompt + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + call StopShellInTerminal(buf) + call assert_equal(2, winnr('$')) + quit + call assert_equal(1, winnr('$')) + + exe 'terminal ++close ' . cmd + call assert_equal(2, winnr('$')) + wincmd p + call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime) + + call term_start(cmd, {'term_finish': 'close'}) + call assert_equal(2, winnr('$')) + wincmd p + call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime) + call assert_equal(1, winnr('$')) + + exe 'terminal ++open ' . cmd + close! + call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) + bwipe + + call term_start(cmd, {'term_finish': 'open'}) + close! + call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) + bwipe + + exe 'terminal ++hidden ++open ' . cmd + call assert_equal(1, winnr('$')) + call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) + bwipe + + call term_start(cmd, {'term_finish': 'open', 'hidden': 1}) + call assert_equal(1, winnr('$')) + call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) + bwipe + + call assert_fails("call term_start(cmd, {'term_opencmd': 'open'})", 'E475:') + call assert_fails("call term_start(cmd, {'term_opencmd': 'split %x'})", 'E475:') + call assert_fails("call term_start(cmd, {'term_opencmd': 'split %d and %s'})", 'E475:') + call assert_fails("call term_start(cmd, {'term_opencmd': 'split % and %d'})", 'E475:') + + call term_start(cmd, {'term_finish': 'open', 'term_opencmd': '4split | buffer %d | let g:result = "opened the buffer in a window"'}) + close! + call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) + call assert_equal(4, winheight(0)) + call assert_equal('opened the buffer in a window', g:result) + unlet g:result + bwipe +endfunc + +func Test_terminal_cwd() + if has('win32') + let cmd = 'cmd /c cd' + else + CheckExecutable pwd + let cmd = 'pwd' + endif + call mkdir('Xtermdir') + let buf = term_start(cmd, {'cwd': 'Xtermdir'}) + " if the path is very long it may be split over two lines, join them + " together + call WaitForAssert({-> assert_equal('Xtermdir', fnamemodify(getline(1) .. getline(2), ":t"))}) + + exe buf . 'bwipe' + call delete('Xtermdir', 'rf') +endfunc + +func Test_terminal_cwd_failure() + " Case 1: Provided directory is not actually a directory. Attempt to make + " the file executable as well. + call writefile([], 'Xtcfile', 'D') + call setfperm('Xtcfile', 'rwx------') + call assert_fails("call term_start(&shell, {'cwd': 'Xtcfile'})", 'E475:') + + " Case 2: Directory does not exist. + call assert_fails("call term_start(&shell, {'cwd': 'Xdir'})", 'E475:') + + " Case 3: Directory exists but is not accessible. + " Skip this for root, it will be accessible anyway. + if !IsRoot() + call mkdir('XdirNoAccess', '', '0600') + " return early if the directory permissions could not be set properly + if getfperm('XdirNoAccess')[2] == 'x' + call delete('XdirNoAccess', 'rf') + return + endif + call assert_fails("call term_start(&shell, {'cwd': 'XdirNoAccess'})", 'E475:') + call delete('XdirNoAccess', 'rf') + endif +endfunc + +func Test_terminal_servername() + CheckFeature clientserver + call s:test_environment("VIM_SERVERNAME", v:servername) +endfunc + +func Test_terminal_version() + call s:test_environment("VIM_TERMINAL", string(v:version)) +endfunc + +func s:test_environment(name, value) + let buf = Run_shell_in_terminal({}) + " Wait for the shell to display a prompt + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + if has('win32') + call term_sendkeys(buf, "echo %" . a:name . "%\r") + else + call term_sendkeys(buf, "echo $" . a:name . "\r") + endif + call TermWait(buf) + call StopShellInTerminal(buf) + call WaitForAssert({-> assert_equal(a:value, getline(2))}) + + exe buf . 'bwipe' + unlet buf +endfunc + +func Test_terminal_env() + let buf = Run_shell_in_terminal({'env': {'TESTENV': 'correct'}}) + " Wait for the shell to display a prompt + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + if has('win32') + call term_sendkeys(buf, "echo %TESTENV%\r") + else + call term_sendkeys(buf, "echo $TESTENV\r") + endif + eval buf->TermWait() + call StopShellInTerminal(buf) + call WaitForAssert({-> assert_equal('correct', getline(2))}) + + exe buf . 'bwipe' +endfunc + +func Test_terminal_list_args() + let buf = term_start([&shell, &shellcmdflag, 'echo "123"']) + call assert_fails(buf . 'bwipe', 'E948:') + exe buf . 'bwipe!' + call assert_equal("", bufname(buf)) +endfunction + +func Test_terminal_noblock() + let g:test_is_flaky = 1 + let buf = term_start(&shell) + " Starting a terminal can be slow, esp. on busy CI machines. + let wait_time = 7500 + let letters = 'abcdefghijklmnopqrstuvwxyz' + if has('bsd') || has('mac') || has('sun') + " The shell or something else has a problem dealing with more than 1000 + " characters at the same time. It's very slow too. + let len = 1000 + let wait_time = 15000 + let letters = 'abcdefghijklm' + " NPFS is used in Windows, nonblocking mode does not work properly. + elseif has('win32') + let len = 1 + else + let len = 5000 + endif + + " Send a lot of text lines, should be buffered properly. + for c in split(letters, '\zs') + call term_sendkeys(buf, 'echo ' . repeat(c, len) . "\<cr>") + endfor + call term_sendkeys(buf, "echo done\<cr>") + + " On MS-Windows there is an extra empty line below "done". Find "done" in + " the last-but-one or the last-but-two line. + let lnum = term_getsize(buf)[0] - 1 + call WaitForAssert({-> assert_match('done', term_getline(buf, lnum - 1) .. '//' .. term_getline(buf, lnum))}, wait_time) + let line = term_getline(buf, lnum) + if line !~ 'done' + let line = term_getline(buf, lnum - 1) + endif + call assert_match('done', line) + + let g:job = term_getjob(buf) + call StopShellInTerminal(buf) + unlet g:job + bwipe +endfunc + +func Test_terminal_write_stdin() + " TODO: enable once writing to stdin works on MS-Windows + CheckNotMSWindows + CheckExecutable wc + let g:test_is_flaky = 1 + + call setline(1, ['one', 'two', 'three']) + %term wc + call WaitForAssert({-> assert_match('3', getline("$"))}) + let nrs = split(getline('$')) + call assert_equal(['3', '3', '14'], nrs) + %bwipe! + + call setline(1, ['one', 'two', 'three', 'four']) + 2,3term wc + call WaitForAssert({-> assert_match('2', getline("$"))}) + let nrs = split(getline('$')) + call assert_equal(['2', '2', '10'], nrs) + %bwipe! +endfunc + +func Test_terminal_eof_arg() + call CheckPython(s:python) + let g:test_is_flaky = 1 + + call setline(1, ['print("hello")']) + exe '1term ++eof=exit(123) ' .. s:python + " MS-Windows echoes the input, Unix doesn't. + if has('win32') + call WaitFor({-> getline('$') =~ 'exit(123)'}) + call assert_equal('hello', getline(line('$') - 1)) + else + call WaitFor({-> getline('$') =~ 'hello'}) + call assert_equal('hello', getline('$')) + endif + call assert_equal(123, bufnr()->term_getjob()->job_info().exitval) + %bwipe! +endfunc + +func Test_terminal_eof_arg_win32_ctrl_z() + CheckMSWindows + call CheckPython(s:python) + let g:test_is_flaky = 1 + + call setline(1, ['print("hello")']) + exe '1term ++eof=<C-Z> ' .. s:python + call WaitForAssert({-> assert_match('\^Z', getline(line('$') - 1))}) + call assert_match('\^Z', getline(line('$') - 1)) + %bwipe! +endfunc + +func Test_terminal_duplicate_eof_arg() + call CheckPython(s:python) + let g:test_is_flaky = 1 + + " Check the last specified ++eof arg is used and does not leak memory. + new + call setline(1, ['print("hello")']) + exe '1term ++eof=<C-Z> ++eof=exit(123) ' .. s:python + " MS-Windows echoes the input, Unix doesn't. + if has('win32') + call WaitFor({-> getline('$') =~ 'exit(123)'}) + call assert_equal('hello', getline(line('$') - 1)) + else + call WaitFor({-> getline('$') =~ 'hello'}) + call assert_equal('hello', getline('$')) + endif + call assert_equal(123, bufnr()->term_getjob()->job_info().exitval) + %bwipe! +endfunc + +func Test_terminal_no_cmd() + let g:test_is_flaky = 1 + let buf = term_start('NONE', {}) + call assert_notequal(0, buf) + + let pty = job_info(term_getjob(buf))['tty_out'] + call assert_notequal('', pty) + if has('gui_running') && !has('win32') + " In the GUI job_start() doesn't work, it does not read from the pty. + call system('echo "look here" > ' . pty) + else + " Otherwise using a job works on all systems. + call job_start([&shell, &shellcmdflag, 'echo "look here" > ' . pty]) + endif + call WaitForAssert({-> assert_match('look here', term_getline(buf, 1))}) + + bwipe! +endfunc + +func Test_terminal_special_chars() + " this file name only works on Unix + CheckUnix + + call mkdir('Xdir with spaces', 'R') + call writefile(['x'], 'Xdir with spaces/quoted"file') + term ls Xdir\ with\ spaces/quoted\"file + call WaitForAssert({-> assert_match('quoted"file', term_getline('', 1))}) + " make sure the job has finished + call WaitForAssert({-> assert_match('finish', term_getstatus(bufnr()))}) + + bwipe +endfunc + +func Test_terminal_wrong_options() + call assert_fails('call term_start(&shell, { + \ "in_io": "file", + \ "in_name": "xxx", + \ "out_io": "file", + \ "out_name": "xxx", + \ "err_io": "file", + \ "err_name": "xxx" + \ })', 'E474:') + call assert_fails('call term_start(&shell, { + \ "out_buf": bufnr("%") + \ })', 'E474:') + call assert_fails('call term_start(&shell, { + \ "err_buf": bufnr("%") + \ })', 'E474:') +endfunc + +func Test_terminal_redir_file() + let g:test_is_flaky = 1 + let cmd = Get_cat_123_cmd() + let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xtrfile'}) + call TermWait(buf) + " ConPTY may precede escape sequence. There are things that are not so. + if !has('conpty') + call WaitForAssert({-> assert_notequal(0, len(readfile("Xtrfile")))}) + call assert_match('123', readfile('Xtrfile')[0]) + endif + let g:job = term_getjob(buf) + call WaitForAssert({-> assert_equal("dead", job_status(g:job))}) + + if has('win32') + " On Windows we cannot delete a file being used by a process. When + " job_status() returns "dead", the process remains for a short time. + " Just wait for a moment. + sleep 50m + endif + call delete('Xtrfile') + bwipe + + if has('unix') + call writefile(['one line'], 'Xtrfile', 'D') + let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xtrfile'}) + call TermWait(buf) + call WaitForAssert({-> assert_equal('one line', term_getline(buf, 1))}) + let g:job = term_getjob(buf) + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + bwipe + endif +endfunc + +func TerminalTmap(remap) + let buf = Run_shell_in_terminal({}) + " Wait for the shell to display a prompt + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + call assert_equal('t', mode()) + + if a:remap + tmap 123 456 + else + tnoremap 123 456 + endif + " don't use abcde, it's an existing command + tmap 456 abxde + call assert_equal('456', maparg('123', 't')) + call assert_equal('abxde', maparg('456', 't')) + call feedkeys("123", 'tx') + call WaitForAssert({-> assert_match('abxde\|456', term_getline(buf, term_getcursor(buf)[0]))}) + let lnum = term_getcursor(buf)[0] + if a:remap + call assert_match('abxde', term_getline(buf, lnum)) + else + call assert_match('456', term_getline(buf, lnum)) + endif + + call term_sendkeys(buf, "\r") + call StopShellInTerminal(buf) + + tunmap 123 + tunmap 456 + call assert_equal('', maparg('123', 't')) + exe buf . 'bwipe' + unlet g:job +endfunc + +func Test_terminal_tmap() + call TerminalTmap(1) + call TerminalTmap(0) +endfunc + +func Test_terminal_wall() + let buf = Run_shell_in_terminal({}) + wall + call StopShellInTerminal(buf) + exe buf . 'bwipe' + unlet g:job +endfunc + +func Test_terminal_wqall() + let buf = Run_shell_in_terminal({}) + call assert_fails('wqall', 'E948:') + call StopShellInTerminal(buf) + exe buf . 'bwipe' + unlet g:job +endfunc + +func Test_terminal_composing_unicode() + let g:test_is_flaky = 1 + let save_enc = &encoding + set encoding=utf-8 + + if has('win32') + let cmd = "cmd /K chcp 65001" + let lnum = [3, 6, 9] + else + let cmd = &shell + let lnum = [1, 3, 5] + endif + + enew + let buf = term_start(cmd, {'curwin': 1}) + let g:job = term_getjob(buf) + call WaitFor({-> term_getline(buf, 1) !=# ''}, 1000) + + if has('win32') + call assert_equal('cmd', job_info(g:job).cmd[0]) + else + call assert_equal(&shell, job_info(g:job).cmd[0]) + endif + + " ascii + composing + let txt = "a\u0308bc" + call term_sendkeys(buf, "echo " . txt) + call TermWait(buf, 25) + call assert_match("echo " . txt, term_getline(buf, lnum[0])) + call term_sendkeys(buf, "\<cr>") + call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[0] + 1))}, 1000) + let l = term_scrape(buf, lnum[0] + 1) + call assert_equal("a\u0308", l[0].chars) + call assert_equal("b", l[1].chars) + call assert_equal("c", l[2].chars) + + " multibyte + composing: がぎぐげご + let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099" + call term_sendkeys(buf, "echo " . txt) + call TermWait(buf, 25) + call assert_match("echo " . txt, term_getline(buf, lnum[1])) + call term_sendkeys(buf, "\<cr>") + call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[1] + 1))}, 1000) + let l = term_scrape(buf, lnum[1] + 1) + call assert_equal("\u304b\u3099", l[0].chars) + call assert_equal(2, l[0].width) + call assert_equal("\u304e", l[1].chars) + call assert_equal(2, l[1].width) + call assert_equal("\u304f\u3099", l[2].chars) + call assert_equal(2, l[2].width) + call assert_equal("\u3052", l[3].chars) + call assert_equal(2, l[3].width) + call assert_equal("\u3053\u3099", l[4].chars) + call assert_equal(2, l[4].width) + + " \u00a0 + composing + let txt = "abc\u00a0\u0308" + call term_sendkeys(buf, "echo " . txt) + call TermWait(buf, 25) + call assert_match("echo " . txt, term_getline(buf, lnum[2])) + call term_sendkeys(buf, "\<cr>") + call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[2] + 1))}, 1000) + let l = term_scrape(buf, lnum[2] + 1) + call assert_equal("\u00a0\u0308", l[3].chars) + + call term_sendkeys(buf, "exit\r") + call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) + bwipe! + unlet g:job + let &encoding = save_enc +endfunc + +func Test_terminal_aucmd_on_close() + fun Nop() + let s:called = 1 + endfun + + aug repro + au! + au BufWinLeave * call Nop() + aug END + + let [cmd, waittime] = s:get_sleep_cmd() + + call assert_equal(1, winnr('$')) + new + call setline(1, ['one', 'two']) + exe 'term ++close ' . cmd + wincmd p + call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime) + call assert_equal(1, s:called) + bwipe! + + unlet s:called + au! repro + delfunc Nop +endfunc + +func Test_terminal_term_start_empty_command() + let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})" + call assert_fails(cmd, 'E474:') + let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})" + call assert_fails(cmd, 'E474:') + let cmd = "call term_start({}, {'curwin' : 1, 'term_finish' : 'close'})" + call assert_fails(cmd, 'E474:') + let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})" + call assert_fails(cmd, 'E474:') + let cmd = "call term_start('', {'term_name' : []})" + call assert_fails(cmd, 'E730:') + let cmd = "call term_start('', {'term_finish' : 'axby'})" + call assert_fails(cmd, 'E475:') + let cmd = "call term_start('', {'eof_chars' : []})" + call assert_fails(cmd, 'E730:') + let cmd = "call term_start('', {'term_kill' : []})" + call assert_fails(cmd, 'E730:') + let cmd = "call term_start('', {'tty_type' : []})" + call assert_fails(cmd, 'E730:') + let cmd = "call term_start('', {'tty_type' : 'abc'})" + call assert_fails(cmd, 'E475:') + let cmd = "call term_start('', {'term_highlight' : []})" + call assert_fails(cmd, 'E730:') + if has('gui') || has('termguicolors') + let cmd = "call term_start('', {'ansi_colors' : 'abc'})" + call assert_fails(cmd, 'E475:') + let cmd = "call term_start('', {'ansi_colors' : [[]]})" + call assert_fails(cmd, 'E730:') + let cmd = "call term_start('', {'ansi_colors' : repeat(['blue'], 18)})" + if has('gui_running') || has('termguicolors') + call assert_fails(cmd, 'E475:') + else + call assert_fails(cmd, 'E254:') + endif + endif +endfunc + +func Test_terminal_response_to_control_sequence() + CheckUnix + + let buf = Run_shell_in_terminal({}) + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + + call term_sendkeys(buf, "cat\<CR>") + call WaitForAssert({-> assert_match('cat', term_getline(buf, 1))}) + + " Request the cursor position. + call term_sendkeys(buf, "\x1b[6n\<CR>") + + " Wait for output from tty to display, below an empty line. + call WaitForAssert({-> assert_match('3;1R', term_getline(buf, 4))}) + + " End "cat" gently. + call term_sendkeys(buf, "\<CR>\<C-D>") + + call StopShellInTerminal(buf) + exe buf . 'bwipe' + unlet g:job +endfunc + +" Run this first, it fails when run after other tests. +func Test_aa_terminal_focus_events() + CheckNotGui + CheckUnix + CheckRunVimInTerminal + + let save_term = &term + let save_ttymouse = &ttymouse + set term=xterm ttymouse=xterm2 + + let lines =<< trim END + set term=xterm ttymouse=xterm2 + au FocusLost * call setline(1, 'I am lost') | set nomod + au FocusGained * call setline(1, 'I am back') | set nomod + END + call writefile(lines, 'XtermFocus', 'D') + let buf = RunVimInTerminal('-S XtermFocus', #{rows: 6}) + + " Send a focus event to ourselves, it should be forwarded to the terminal + call feedkeys("\<Esc>[O", "Lx!") + call VerifyScreenDump(buf, 'Test_terminal_focus_1', {}) + + call feedkeys("\<Esc>[I", "Lx!") + call VerifyScreenDump(buf, 'Test_terminal_focus_2', {}) + + " check that a command line being edited is redrawn in place + call term_sendkeys(buf, ":" .. repeat('x', 80)) + call TermWait(buf) + call feedkeys("\<Esc>[O", "Lx!") + call VerifyScreenDump(buf, 'Test_terminal_focus_3', {}) + call term_sendkeys(buf, "\<Esc>") + + call StopVimInTerminal(buf) + let &term = save_term + let &ttymouse = save_ttymouse +endfunc + +" Run Vim, start a terminal in that Vim with the kill argument, +" :qall works. +func Run_terminal_qall_kill(line1, line2) + " 1. Open a terminal window and wait for the prompt to appear + " 2. set kill using term_setkill() + " 3. make Vim exit, it will kill the shell + let after = [ + \ a:line1, + \ 'let buf = bufnr("%")', + \ 'while term_getline(buf, 1) =~ "^\\s*$"', + \ ' sleep 10m', + \ 'endwhile', + \ a:line2, + \ 'au VimLeavePre * call writefile(["done"], "Xdone")', + \ 'qall', + \ ] + if !RunVim([], after, '') + return + endif + call assert_equal("done", readfile("Xdone")[0]) + call delete("Xdone") +endfunc + +" Run Vim in a terminal, then start a terminal in that Vim with a kill +" argument, check that :qall works. +func Test_terminal_qall_kill_arg() + call Run_terminal_qall_kill('term ++kill=kill', '') +endfunc + +" Run Vim, start a terminal in that Vim, set the kill argument with +" term_setkill(), check that :qall works. +func Test_terminal_qall_kill_func() + call Run_terminal_qall_kill('term', 'eval buf->term_setkill("kill")') +endfunc + +" Run Vim, start a terminal in that Vim without the kill argument, +" check that :qall does not exit, :qall! does. +func Test_terminal_qall_exit() + let after =<< trim [CODE] + term + let buf = bufnr("%") + while term_getline(buf, 1) =~ "^\\s*$" + sleep 10m + endwhile + set nomore + au VimLeavePre * call writefile(["too early"], "Xdone") + qall + au! VimLeavePre * exe buf . "bwipe!" | call writefile(["done"], "Xdone") + cquit + [CODE] + + if !RunVim([], after, '') + return + endif + call assert_equal("done", readfile("Xdone")[0]) + call delete("Xdone") +endfunc + +" Run Vim in a terminal, then start a terminal in that Vim without a kill +" argument, check that :confirm qall works. +func Test_terminal_qall_prompt() + CheckRunVimInTerminal + + let buf = RunVimInTerminal('', {}) + + " the shell may set the window title, we don't want that here + call term_sendkeys(buf, ":call test_override('vterm_title', 1)\<CR>") + + " Open a terminal window and wait for the prompt to appear + call term_sendkeys(buf, ":term\<CR>") + call WaitForAssert({-> assert_match('\[running]', term_getline(buf, 10))}) + call WaitForAssert({-> assert_notmatch('^\s*$', term_getline(buf, 1))}) + + " make Vim exit, it will prompt to kill the shell + call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>") + call WaitForAssert({-> assert_match('\[Y\]es, (N)o:', term_getline(buf, 20))}) + call term_sendkeys(buf, "y") + call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))}) + + " close the terminal window where Vim was running + quit +endfunc + +" Run Vim in a terminal, then start a terminal window with a shell and check +" that Vim exits if it is closed. +func Test_terminal_exit() + CheckRunVimInTerminal + + let lines =<< trim END + let winid = win_getid() + help + term + let termid = win_getid() + call win_gotoid(winid) + close + call win_gotoid(termid) + END + call writefile(lines, 'XtermExit', 'D') + let buf = RunVimInTerminal('-S XtermExit', #{rows: 10}) + let job = term_getjob(buf) + call WaitForAssert({-> assert_equal("run", job_status(job))}) + + " quit the shell, it will make Vim exit + call term_sendkeys(buf, "exit\<CR>") + call WaitForAssert({-> assert_equal("dead", job_status(job))}) +endfunc + +func Test_terminal_open_autocmd() + augroup repro + au! + au TerminalOpen * let s:called += 1 + augroup END + + let s:called = 0 + + " Open a terminal window with :terminal + terminal + call assert_equal(1, s:called) + bwipe! + + " Open a terminal window with term_start() + call term_start(&shell) + call assert_equal(2, s:called) + bwipe! + + " Open a hidden terminal buffer with :terminal + terminal ++hidden + call assert_equal(3, s:called) + for buf in term_list() + exe buf . "bwipe!" + endfor + + " Open a hidden terminal buffer with term_start() + let buf = term_start(&shell, {'hidden': 1}) + call assert_equal(4, s:called) + exe buf . "bwipe!" + + unlet s:called + au! repro +endfunc + +func Test_open_term_from_cmd() + CheckUnix + CheckRunVimInTerminal + + let lines =<< trim END + call setline(1, ['a', 'b', 'c']) + 3 + set incsearch + cnoremap <F3> <Cmd>call term_start(['/bin/sh', '-c', ':'])<CR> + END + call writefile(lines, 'Xopenterm', 'D') + let buf = RunVimInTerminal('-S Xopenterm', {}) + + " this opens a window, incsearch should not use the old cursor position + call term_sendkeys(buf, "/\<F3>") + call VerifyScreenDump(buf, 'Test_terminal_from_cmd', {}) + call term_sendkeys(buf, "\<Esc>") + call term_sendkeys(buf, ":q\<CR>") + + call StopVimInTerminal(buf) +endfunc + +func Test_combining_double_width() + CheckUnix + CheckRunVimInTerminal + + call writefile(["\xe3\x83\x9b\xe3\x82\x9a"], 'Xonedouble', 'D') + let lines =<< trim END + call term_start(['/bin/sh', '-c', 'cat Xonedouble']) + END + call writefile(lines, 'Xcombining', 'D') + let buf = RunVimInTerminal('-S Xcombining', #{rows: 9}) + + " this opens a window, incsearch should not use the old cursor position + call VerifyScreenDump(buf, 'Test_terminal_combining', {}) + call term_sendkeys(buf, ":q\<CR>") + + call StopVimInTerminal(buf) +endfunc + +func Test_terminal_popup_with_cmd() + " this was crashing + let buf = term_start(&shell, #{hidden: v:true}) + let s:winid = popup_create(buf, {}) + tnoremap <F3> <Cmd>call popup_close(s:winid)<CR> + call feedkeys("\<F3>", 'xt') + + tunmap <F3> + exe 'bwipe! ' .. buf + unlet s:winid +endfunc + +func Test_terminal_popup_bufload() + let termbuf = term_start(&shell, #{hidden: v:true, term_finish: 'close'}) + let winid = popup_create(termbuf, {}) + sleep 50m + + let newbuf = bufadd('') + call bufload(newbuf) + call setbufline(newbuf, 1, 'foobar') + + " must not have switched to another window + call assert_equal(winid, win_getid()) + + call StopShellInTerminal(termbuf) + call WaitFor({-> win_getid() != winid}) + exe 'bwipe! ' .. newbuf +endfunc + +func Test_terminal_popup_two_windows() + CheckRunVimInTerminal + CheckUnix + + " use "sh" instead of "&shell" in the hope it will use a short prompt + let lines =<< trim END + let termbuf = term_start('sh', #{hidden: v:true, term_finish: 'close'}) + exe 'buffer ' .. termbuf + + let winid = popup_create(termbuf, #{line: 2, minwidth: 30, border: []}) + sleep 50m + + call term_sendkeys(termbuf, "echo 'test'") + END + call writefile(lines, 'XpopupScript', 'D') + let buf = RunVimInTerminal('-S XpopupScript', {}) + + " typed text appears both in normal window and in popup + call WaitForAssert({-> assert_match("echo 'test'", term_getline(buf, 1))}) + call WaitForAssert({-> assert_match("echo 'test'", term_getline(buf, 3))}) + + call term_sendkeys(buf, "\<CR>\<CR>exit\<CR>") + call TermWait(buf) + call term_sendkeys(buf, ":q\<CR>") + call StopVimInTerminal(buf) +endfunc + +func Test_terminal_popup_insert_cmd() + CheckUnix + + inoremap <F3> <Cmd>call StartTermInPopup()<CR> + func StartTermInPopup() + call term_start(['/bin/sh', '-c', 'cat'], #{hidden: v:true, term_finish: 'close'})->popup_create(#{highlight: 'Pmenu'}) + endfunc + call feedkeys("i\<F3>") + sleep 10m + call assert_equal('n', mode()) + + call feedkeys("\<C-D>", 'xt') + call WaitFor({-> popup_list() == []}) + delfunc StartTermInPopup + iunmap <F3> +endfunc + +func Check_dump01(off) + call assert_equal('one two three four five', trim(getline(a:off + 1))) + call assert_equal('~ Select Word', trim(getline(a:off + 7))) + call assert_equal(':popup PopUp', trim(getline(a:off + 20))) +endfunc + +func Test_terminal_dumpwrite_composing() + CheckRunVimInTerminal + + let save_enc = &encoding + set encoding=utf-8 + call assert_equal(1, winnr('$')) + + let text = " a\u0300 e\u0302 o\u0308" + call writefile([text], 'Xcomposing', 'D') + let buf = RunVimInTerminal('--cmd "set encoding=utf-8" Xcomposing', {}) + call WaitForAssert({-> assert_match(text, term_getline(buf, 1))}) + eval 'Xdump'->term_dumpwrite(buf) + let dumpline = readfile('Xdump')[0] + call assert_match('|à| |ê| |ö', dumpline) + + call StopVimInTerminal(buf) + call delete('Xdump') + let &encoding = save_enc +endfunc + +" Tests for failures in the term_dumpwrite() function +func Test_terminal_dumpwrite_errors() + CheckRunVimInTerminal + call assert_fails("call term_dumpwrite({}, 'Xtest.dump')", 'E728:') + let buf = RunVimInTerminal('', {}) + call TermWait(buf) + call assert_fails("call term_dumpwrite(buf, 'Xtest.dump', '')", 'E1206:') + call assert_fails("call term_dumpwrite(buf, [])", 'E730:') + call writefile([], 'Xtest.dump') + call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E953:') + call delete('Xtest.dump') + call assert_fails("call term_dumpwrite(buf, '')", 'E482:') + call assert_fails("call term_dumpwrite(buf, test_null_string())", 'E482:') + call test_garbagecollect_now() + call StopVimInTerminal(buf, 0) + call TermWait(buf) + call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E958:') + call assert_fails('call term_sendkeys([], ":q\<CR>")', 'E745:') + call assert_equal(0, term_sendkeys(buf, ":q\<CR>")) +endfunc + +" just testing basic functionality. +func Test_terminal_dumpload() + let curbuf = winbufnr('') + call assert_equal(1, winnr('$')) + let buf = term_dumpload('dumps/Test_popup_command_01.dump') + call assert_equal(2, winnr('$')) + call assert_equal(20, line('$')) + call Check_dump01(0) + + " Load another dump in the same window + let buf2 = 'dumps/Test_diff_01.dump'->term_dumpload({'bufnr': buf}) + call assert_equal(buf, buf2) + call assert_notequal('one two three four five', trim(getline(1))) + + " Load the first dump again in the same window + let buf2 = term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': buf}) + call assert_equal(buf, buf2) + call Check_dump01(0) + + call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': curbuf})", 'E475:') + call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': 9999})", 'E86:') + new + let closedbuf = winbufnr('') + quit + call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': closedbuf})", 'E475:') + call assert_fails('call term_dumpload([])', 'E730:') + call assert_fails('call term_dumpload("xabcy.dump")', 'E485:') + + quit +endfunc + +func Test_terminal_dumpload_dump() + CheckRunVimInTerminal + + let lines =<< trim END + call term_dumpload('dumps/Test_popupwin_22.dump', #{term_rows: 12}) + END + call writefile(lines, 'XtermDumpload', 'D') + let buf = RunVimInTerminal('-S XtermDumpload', #{rows: 15}) + call VerifyScreenDump(buf, 'Test_terminal_dumpload', {}) + + call StopVimInTerminal(buf) +endfunc + +func Test_terminal_dumpdiff() + call assert_equal(1, winnr('$')) + eval 'dumps/Test_popup_command_01.dump'->term_dumpdiff('dumps/Test_popup_command_02.dump') + call assert_equal(2, winnr('$')) + call assert_equal(62, line('$')) + call Check_dump01(0) + call Check_dump01(42) + call assert_equal(' bbbbbbbbbbbbbbbbbb ', getline(26)[0:29]) + quit + + call assert_fails('call term_dumpdiff("X1.dump", [])', 'E730:') + call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:') + call writefile([], 'X1.dump', 'D') + call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:') +endfunc + +func Test_terminal_dumpdiff_swap() + call assert_equal(1, winnr('$')) + call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_03.dump') + call assert_equal(2, winnr('$')) + call assert_equal(62, line('$')) + call assert_match('Test_popup_command_01.dump', getline(21)) + call assert_match('Test_popup_command_03.dump', getline(42)) + call assert_match('Undo', getline(3)) + call assert_match('three four five', getline(45)) + + normal s + call assert_match('Test_popup_command_03.dump', getline(21)) + call assert_match('Test_popup_command_01.dump', getline(42)) + call assert_match('three four five', getline(3)) + call assert_match('Undo', getline(45)) + quit + + " Diff two terminal dump files with different number of rows + " Swap the diffs + call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_winline_rnu.dump') + call assert_match('Test_popup_command_01.dump', getline(21)) + call assert_match('Test_winline_rnu.dump', getline(42)) + normal s + call assert_match('Test_winline_rnu.dump', getline(6)) + call assert_match('Test_popup_command_01.dump', getline(27)) + quit +endfunc + +func Test_terminal_dumpdiff_options() + set laststatus=0 + call assert_equal(1, winnr('$')) + let height = winheight(0) + call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 1, 'term_cols': 33}) + call assert_equal(2, winnr('$')) + call assert_equal(height, winheight(winnr())) + call assert_equal(33, winwidth(winnr())) + call assert_equal('dump diff dumps/Test_popup_command_01.dump', bufname('%')) + quit + + call assert_equal(1, winnr('$')) + call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 0, 'term_rows': 13, 'term_name': 'something else'}) + call assert_equal(2, winnr('$')) + call assert_equal(&columns, winwidth(0)) + call assert_equal(13, winheight(0)) + call assert_equal('something else', bufname('%')) + quit + + call assert_equal(1, winnr('$')) + call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1}) + call assert_equal(1, winnr('$')) + call assert_fails("call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'bufnr': -1})", 'E475:') + bwipe + + set laststatus& +endfunc + +" When drawing the statusline the cursor position may not have been updated +" yet. +" 1. create a terminal, make it show 2 lines +" 2. 0.5 sec later: leave terminal window, execute "i" +" 3. 0.5 sec later: clear terminal window, now it's 1 line +" 4. 0.5 sec later: redraw, including statusline (used to trigger bug) +" 4. 0.5 sec later: should be done, clean up +func Test_terminal_statusline() + CheckUnix + CheckFeature timers + + set statusline=x + terminal + let tbuf = bufnr('') + call term_sendkeys(tbuf, "clear; echo a; echo b; sleep 1; clear\n") + call timer_start(500, { tid -> feedkeys("\<C-w>j", 'tx') }) + call timer_start(1500, { tid -> feedkeys("\<C-l>", 'tx') }) + au BufLeave * if &buftype == 'terminal' | silent! normal i | endif + + sleep 2 + exe tbuf . 'bwipe!' + au! BufLeave + set statusline= +endfunc + +func CheckTerminalWindowWorks(buf) + call WaitForAssert({-> assert_match('!sh \[running\]', term_getline(a:buf, 10))}) + call term_sendkeys(a:buf, "exit\<CR>") + call WaitForAssert({-> assert_match('!sh \[finished\]', term_getline(a:buf, 10))}) + call term_sendkeys(a:buf, ":q\<CR>") + call WaitForAssert({-> assert_match('^\~', term_getline(a:buf, 10))}) +endfunc + +func Test_start_terminal_from_timer() + CheckUnix + CheckFeature timers + + " Open a terminal window from a timer, typed text goes to the terminal + call writefile(["call timer_start(100, { -> term_start('sh') })"], 'XtimerTerm', 'D') + let buf = RunVimInTerminal('-S XtimerTerm', {}) + call CheckTerminalWindowWorks(buf) + + " do the same in Insert mode + call term_sendkeys(buf, ":call timer_start(200, { -> term_start('sh') })\<CR>a") + call CheckTerminalWindowWorks(buf) + + call StopVimInTerminal(buf) +endfunc + +func Test_terminal_window_focus() + let winid1 = win_getid() + terminal + let winid2 = win_getid() + call feedkeys("\<C-W>j", 'xt') + call assert_equal(winid1, win_getid()) + call feedkeys("\<C-W>k", 'xt') + call assert_equal(winid2, win_getid()) + " can use a cursor key here + call feedkeys("\<C-W>\<Down>", 'xt') + call assert_equal(winid1, win_getid()) + call feedkeys("\<C-W>\<Up>", 'xt') + call assert_equal(winid2, win_getid()) + + bwipe! +endfunc + +func Api_drop_common(options) + call assert_equal(1, winnr('$')) + + " Use the title termcap entries to output the escape sequence. + call writefile([ + \ 'set title', + \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"', + \ 'let &titlestring = ''["drop","Xtextfile"' . a:options . ']''', + \ 'redraw', + \ "set t_ts=", + \ ], 'Xscript') + let buf = RunVimInTerminal('-S Xscript', {}) + call WaitFor({-> bufnr('Xtextfile') > 0}) + call assert_equal('Xtextfile', expand('%:t')) + call assert_true(winnr('$') >= 3) + return buf +endfunc + +func Test_terminal_api_drop_newwin() + CheckRunVimInTerminal + let buf = Api_drop_common('') + call assert_equal(0, &bin) + call assert_equal('', &fenc) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile +endfunc + +func Test_terminal_api_drop_newwin_bin() + CheckRunVimInTerminal + let buf = Api_drop_common(',{"bin":1}') + call assert_equal(1, &bin) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile +endfunc + +func Test_terminal_api_drop_newwin_binary() + CheckRunVimInTerminal + let buf = Api_drop_common(',{"binary":1}') + call assert_equal(1, &bin) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile +endfunc + +func Test_terminal_api_drop_newwin_nobin() + CheckRunVimInTerminal + set binary + let buf = Api_drop_common(',{"nobin":1}') + call assert_equal(0, &bin) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile + set nobinary +endfunc + +func Test_terminal_api_drop_newwin_nobinary() + CheckRunVimInTerminal + set binary + let buf = Api_drop_common(',{"nobinary":1}') + call assert_equal(0, &bin) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile + set nobinary +endfunc + +func Test_terminal_api_drop_newwin_ff() + CheckRunVimInTerminal + let buf = Api_drop_common(',{"ff":"dos"}') + call assert_equal("dos", &ff) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile +endfunc + +func Test_terminal_api_drop_newwin_fileformat() + CheckRunVimInTerminal + let buf = Api_drop_common(',{"fileformat":"dos"}') + call assert_equal("dos", &ff) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile +endfunc + +func Test_terminal_api_drop_newwin_enc() + CheckRunVimInTerminal + let buf = Api_drop_common(',{"enc":"utf-16"}') + call assert_equal("utf-16", &fenc) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile +endfunc + +func Test_terminal_api_drop_newwin_encoding() + CheckRunVimInTerminal + let buf = Api_drop_common(',{"encoding":"utf-16"}') + call assert_equal("utf-16", &fenc) + + call StopVimInTerminal(buf) + call delete('Xscript') + bwipe Xtextfile +endfunc + +func Test_terminal_api_drop_oldwin() + CheckRunVimInTerminal + let firstwinid = win_getid() + split Xtextfile + let textfile_winid = win_getid() + call assert_equal(2, winnr('$')) + call win_gotoid(firstwinid) + + " Use the title termcap entries to output the escape sequence. + call writefile([ + \ 'set title', + \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"', + \ 'let &titlestring = ''["drop","Xtextfile"]''', + \ 'redraw', + \ "set t_ts=", + \ ], 'Xscript', 'D') + let buf = RunVimInTerminal('-S Xscript', {'rows': 10}) + call WaitForAssert({-> assert_equal('Xtextfile', expand('%:t'))}) + call assert_equal(textfile_winid, win_getid()) + + call StopVimInTerminal(buf) + bwipe Xtextfile +endfunc + +func Tapi_TryThis(bufnum, arg) + let g:called_bufnum = a:bufnum + let g:called_arg = a:arg +endfunc + +func WriteApiCall(funcname) + " Use the title termcap entries to output the escape sequence. + call writefile([ + \ 'set title', + \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"', + \ 'let &titlestring = ''["call","' . a:funcname . '",["hello",123]]''', + \ 'redraw', + \ "set t_ts=", + \ ], 'Xscript') +endfunc + +func Test_terminal_api_call() + CheckRunVimInTerminal + + unlet! g:called_bufnum + unlet! g:called_arg + + call WriteApiCall('Tapi_TryThis') + + " Default + let buf = RunVimInTerminal('-S Xscript', {}) + call WaitFor({-> exists('g:called_bufnum')}) + call assert_equal(buf, g:called_bufnum) + call assert_equal(['hello', 123], g:called_arg) + call StopVimInTerminal(buf) + + unlet! g:called_bufnum + unlet! g:called_arg + + " Enable explicitly + let buf = RunVimInTerminal('-S Xscript', {'term_api': 'Tapi_Try'}) + call WaitFor({-> exists('g:called_bufnum')}) + call assert_equal(buf, g:called_bufnum) + call assert_equal(['hello', 123], g:called_arg) + call StopVimInTerminal(buf) + + unlet! g:called_bufnum + unlet! g:called_arg + + func! ApiCall_TryThis(bufnum, arg) + let g:called_bufnum2 = a:bufnum + let g:called_arg2 = a:arg + endfunc + + call WriteApiCall('ApiCall_TryThis') + + " Use prefix match + let buf = RunVimInTerminal('-S Xscript', {'term_api': 'ApiCall_'}) + call WaitFor({-> exists('g:called_bufnum2')}) + call assert_equal(buf, g:called_bufnum2) + call assert_equal(['hello', 123], g:called_arg2) + call StopVimInTerminal(buf) + + call assert_fails("call term_start('ls', {'term_api' : []})", 'E730:') + + unlet! g:called_bufnum2 + unlet! g:called_arg2 + + call delete('Xscript') + delfunction! ApiCall_TryThis + unlet! g:called_bufnum2 + unlet! g:called_arg2 +endfunc + +func Test_terminal_api_call_fails() + CheckRunVimInTerminal + + func! TryThis(bufnum, arg) + let g:called_bufnum3 = a:bufnum + let g:called_arg3 = a:arg + endfunc + + call WriteApiCall('TryThis') + + unlet! g:called_bufnum3 + unlet! g:called_arg3 + + " Not permitted + call ch_logfile('Xlog', 'w') + let buf = RunVimInTerminal('-S Xscript', {'term_api': ''}) + call WaitForAssert({-> assert_match('Unpermitted function: TryThis', string(readfile('Xlog')))}) + call assert_false(exists('g:called_bufnum3')) + call assert_false(exists('g:called_arg3')) + call StopVimInTerminal(buf) + + " No match + call ch_logfile('Xlog', 'w') + let buf = RunVimInTerminal('-S Xscript', {'term_api': 'TryThat'}) + call WaitFor({-> string(readfile('Xlog')) =~ 'Unpermitted function: TryThis'}) + call assert_false(exists('g:called_bufnum3')) + call assert_false(exists('g:called_arg3')) + call StopVimInTerminal(buf) + + call delete('Xscript') + call ch_logfile('') + call delete('Xlog') + delfunction! TryThis + unlet! g:called_bufnum3 + unlet! g:called_arg3 +endfunc + +let s:caught_e937 = 0 + +func Tapi_Delete(bufnum, arg) + try + execute 'bdelete!' a:bufnum + catch /E937:/ + let s:caught_e937 = 1 + endtry +endfunc + +func Test_terminal_api_call_fail_delete() + CheckRunVimInTerminal + + call WriteApiCall('Tapi_Delete') + let buf = RunVimInTerminal('-S Xscript', {}) + call WaitForAssert({-> assert_equal(1, s:caught_e937)}) + + call StopVimInTerminal(buf) + call delete('Xscript') + call ch_logfile('', '') +endfunc + +func Test_terminal_setapi_and_call() + CheckRunVimInTerminal + + call WriteApiCall('Tapi_TryThis') + call ch_logfile('Xlog', 'w') + + unlet! g:called_bufnum + unlet! g:called_arg + + let buf = RunVimInTerminal('-S Xscript', {'term_api': ''}) + call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))}) + call assert_false(exists('g:called_bufnum')) + call assert_false(exists('g:called_arg')) + + eval buf->term_setapi('Tapi_') + call term_sendkeys(buf, ":set notitle\<CR>") + call term_sendkeys(buf, ":source Xscript\<CR>") + call WaitFor({-> exists('g:called_bufnum')}) + call assert_equal(buf, g:called_bufnum) + call assert_equal(['hello', 123], g:called_arg) + + call StopVimInTerminal(buf) + + call delete('Xscript') + call ch_logfile('') + call delete('Xlog') + unlet! g:called_bufnum + unlet! g:called_arg +endfunc + +func Test_terminal_api_arg() + CheckRunVimInTerminal + + call WriteApiCall('Tapi_TryThis') + call ch_logfile('Xlog', 'w') + + unlet! g:called_bufnum + unlet! g:called_arg + + execute 'term ++api= ' .. GetVimCommandCleanTerm() .. '-S Xscript' + let buf = bufnr('%') + call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))}) + call assert_false(exists('g:called_bufnum')) + call assert_false(exists('g:called_arg')) + + call StopVimInTerminal(buf) + + call ch_logfile('Xlog', 'w') + + execute 'term ++api=Tapi_ ' .. GetVimCommandCleanTerm() .. '-S Xscript' + let buf = bufnr('%') + call WaitFor({-> exists('g:called_bufnum')}) + call assert_equal(buf, g:called_bufnum) + call assert_equal(['hello', 123], g:called_arg) + + call StopVimInTerminal(buf) + + call delete('Xscript') + call ch_logfile('') + call delete('Xlog') + unlet! g:called_bufnum + unlet! g:called_arg +endfunc + +func Test_terminal_ansicolors_default() + CheckFunction term_getansicolors + + let colors = [ + \ '#000000', '#e00000', + \ '#00e000', '#e0e000', + \ '#0000e0', '#e000e0', + \ '#00e0e0', '#e0e0e0', + \ '#808080', '#ff4040', + \ '#40ff40', '#ffff40', + \ '#4040ff', '#ff40ff', + \ '#40ffff', '#ffffff', + \] + + let buf = Run_shell_in_terminal({}) + call assert_equal(colors, term_getansicolors(buf)) + call StopShellInTerminal(buf) + call assert_equal([], term_getansicolors(buf)) + + exe buf . 'bwipe' +endfunc + +let s:test_colors = [ + \ '#616e64', '#0d0a79', + \ '#6d610d', '#0a7373', + \ '#690d0a', '#6d696e', + \ '#0d0a6f', '#616e0d', + \ '#0a6479', '#6d0d0a', + \ '#617373', '#0d0a69', + \ '#6d690d', '#0a6e6f', + \ '#610d0a', '#6e6479', + \] + +func Test_terminal_ansicolors_global() + CheckFeature termguicolors + CheckFunction term_getansicolors + + if has('vtp') && !has('vcon') && !has('gui_running') + throw 'Skipped: does not support termguicolors' + endif + + set tgc + let g:terminal_ansi_colors = reverse(copy(s:test_colors)) + let buf = Run_shell_in_terminal({}) + call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf)) + call StopShellInTerminal(buf) + set tgc& + + exe buf . 'bwipe' + unlet g:terminal_ansi_colors +endfunc + +func Test_terminal_ansicolors_func() + CheckFeature termguicolors + CheckFunction term_getansicolors + + if has('vtp') && !has('vcon') && !has('gui_running') + throw 'Skipped: does not support termguicolors' + endif + + set tgc + let g:terminal_ansi_colors = reverse(copy(s:test_colors)) + let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors}) + call assert_equal(s:test_colors, term_getansicolors(buf)) + + call term_setansicolors(buf, g:terminal_ansi_colors) + call assert_equal(g:terminal_ansi_colors, buf->term_getansicolors()) + + let colors = [ + \ 'ivory', 'AliceBlue', + \ 'grey67', 'dark goldenrod', + \ 'SteelBlue3', 'PaleVioletRed4', + \ 'MediumPurple2', 'yellow2', + \ 'RosyBrown3', 'OrangeRed2', + \ 'white smoke', 'navy blue', + \ 'grey47', 'gray97', + \ 'MistyRose2', 'DodgerBlue4', + \] + eval buf->term_setansicolors(colors) + + let colors[4] = 'Invalid' + call assert_fails('call term_setansicolors(buf, colors)', 'E254:') + call assert_fails('call term_setansicolors(buf, {})', 'E1211:') + set tgc& + + call StopShellInTerminal(buf) + call assert_equal(0, term_setansicolors(buf, [])) + exe buf . 'bwipe' +endfunc + +func Test_terminal_all_ansi_colors() + CheckRunVimInTerminal + + " Use all the ANSI colors. + call writefile([ + \ 'call setline(1, "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPP XXYYZZ")', + \ 'hi Tblack ctermfg=0 ctermbg=8', + \ 'hi Tdarkred ctermfg=1 ctermbg=9', + \ 'hi Tdarkgreen ctermfg=2 ctermbg=10', + \ 'hi Tbrown ctermfg=3 ctermbg=11', + \ 'hi Tdarkblue ctermfg=4 ctermbg=12', + \ 'hi Tdarkmagenta ctermfg=5 ctermbg=13', + \ 'hi Tdarkcyan ctermfg=6 ctermbg=14', + \ 'hi Tlightgrey ctermfg=7 ctermbg=15', + \ 'hi Tdarkgrey ctermfg=8 ctermbg=0', + \ 'hi Tred ctermfg=9 ctermbg=1', + \ 'hi Tgreen ctermfg=10 ctermbg=2', + \ 'hi Tyellow ctermfg=11 ctermbg=3', + \ 'hi Tblue ctermfg=12 ctermbg=4', + \ 'hi Tmagenta ctermfg=13 ctermbg=5', + \ 'hi Tcyan ctermfg=14 ctermbg=6', + \ 'hi Twhite ctermfg=15 ctermbg=7', + \ 'hi TdarkredBold ctermfg=1 cterm=bold', + \ 'hi TgreenBold ctermfg=10 cterm=bold', + \ 'hi TmagentaBold ctermfg=13 cterm=bold ctermbg=5', + \ '', + \ 'call matchadd("Tblack", "A")', + \ 'call matchadd("Tdarkred", "B")', + \ 'call matchadd("Tdarkgreen", "C")', + \ 'call matchadd("Tbrown", "D")', + \ 'call matchadd("Tdarkblue", "E")', + \ 'call matchadd("Tdarkmagenta", "F")', + \ 'call matchadd("Tdarkcyan", "G")', + \ 'call matchadd("Tlightgrey", "H")', + \ 'call matchadd("Tdarkgrey", "I")', + \ 'call matchadd("Tred", "J")', + \ 'call matchadd("Tgreen", "K")', + \ 'call matchadd("Tyellow", "L")', + \ 'call matchadd("Tblue", "M")', + \ 'call matchadd("Tmagenta", "N")', + \ 'call matchadd("Tcyan", "O")', + \ 'call matchadd("Twhite", "P")', + \ 'call matchadd("TdarkredBold", "X")', + \ 'call matchadd("TgreenBold", "Y")', + \ 'call matchadd("TmagentaBold", "Z")', + \ 'redraw', + \ ], 'Xcolorscript', 'D') + let buf = RunVimInTerminal('-S Xcolorscript', {'rows': 10}) + call VerifyScreenDump(buf, 'Test_terminal_all_ansi_colors', {}) + + call term_sendkeys(buf, ":q\<CR>") + call StopVimInTerminal(buf) +endfunc + +function On_BufFilePost() + doautocmd <nomodeline> User UserEvent +endfunction + +func Test_terminal_nested_autocmd() + new + call setline(1, range(500)) + $ + let lastline = line('.') + + augroup TermTest + autocmd BufFilePost * call On_BufFilePost() + autocmd User UserEvent silent + augroup END + + let cmd = Get_cat_123_cmd() + let buf = term_start(cmd, #{term_finish: 'close', hidden: 1}) + call assert_equal(lastline, line('.')) + + let job = term_getjob(buf) + call WaitForAssert({-> assert_equal("dead", job_status(job))}) + call delete('Xtext') + augroup TermTest + au! + augroup END +endfunc + +func Test_terminal_adds_jump() + clearjumps + call term_start("ls", #{curwin: 1}) + call assert_equal(1, getjumplist()[0]->len()) + bwipe! +endfunc + +func Close_cb(ch, ctx) + call term_wait(a:ctx.bufnr) + let g:close_done = 'done' +endfunc + +func Test_term_wait_in_close_cb() + let g:close_done = '' + let ctx = {} + let ctx.bufnr = term_start('echo "HELLO WORLD"', + \ {'close_cb': {ch -> Close_cb(ch, ctx)}}) + + call WaitForAssert({-> assert_equal("done", g:close_done)}) + + unlet g:close_done + bwipe! +endfunc + +func Test_term_TextChangedT() + augroup TermTest + autocmd TextChangedT * ++once + \ execute expand('<abuf>') . 'buffer' | + \ let b:called = 1 | + \ split | + \ enew + augroup END + + terminal + + let term_buf = bufnr() + + let b:called = 0 + + call term_sendkeys(term_buf, "aaabbc\r") + call TermWait(term_buf) + + call assert_equal(1, getbufvar(term_buf, 'called')) + + " Current buffer will be restored + call assert_equal(bufnr(), term_buf) + + bwipe! + augroup TermTest + au! + augroup END +endfunc + +func Test_term_TextChangedT_close() + augroup TermTest + autocmd TextChangedT * ++once split | enew | 1close! + augroup END + + terminal + + let term_buf = bufnr() + + call term_sendkeys(term_buf, "aaabbc\r") + call TermWait(term_buf) + + " Current buffer will be restored + call assert_equal(bufnr(), term_buf) + + bwipe! + augroup TermTest + au! + augroup END +endfunc + +" vim: shiftwidth=2 sts=2 expandtab |