Mercurial > vim
view src/testdir/test_autocmd.vim @ 34686:83875247fbc0 v9.1.0224
patch 9.1.0224: cursor may move too many lines over "right" & "below" virt text
Commit: https://github.com/vim/vim/commit/515f734e687f28f7199b2a8042197624d9f3ec15
Author: Dylan Thacker-Smith <dylan.ah.smith@gmail.com>
Date: Thu Mar 28 12:01:14 2024 +0100
patch 9.1.0224: cursor may move too many lines over "right" & "below" virt text
Problem: If a line has "right" & "below" virtual text properties,
where the "below" property may be stored first due to lack of
ordering between them, then the line height is calculated to
be 1 more and causes the cursor to far over the line.
Solution: Remove some unnecessary setting of a
`next_right_goes_below = TRUE` flag for "below" and "above"
text properties. (Dylan Thacker-Smith)
I modified a regression test I recently added to cover this case,
leveraging the fact that "after", "right" & "below" text properties are
being stored in the reverse of the order they are added in. The
previous version of this regression test was crafted to workaround this
issue so it can be addressed by this separate patch.
closes: #14317
Signed-off-by: Dylan Thacker-Smith <dylan.ah.smith@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 28 Mar 2024 12:15:03 +0100 |
parents | 172f30203d25 |
children | d432af20fe54 |
line wrap: on
line source
" Tests for autocommands source shared.vim source check.vim source term_util.vim source screendump.vim import './vim9.vim' as v9 func s:cleanup_buffers() abort for bnr in range(1, bufnr('$')) if bufloaded(bnr) && bufnr('%') != bnr execute 'bd! ' . bnr endif endfor endfunc func Test_vim_did_enter() call assert_false(v:vim_did_enter) " This script will never reach the main loop, can't check if v:vim_did_enter " becomes one. endfunc " Test for the CursorHold autocmd func Test_CursorHold_autocmd() CheckRunVimInTerminal call writefile(['one', 'two', 'three'], 'XoneTwoThree', 'D') let before =<< trim END set updatetime=10 au CursorHold * call writefile([line('.')], 'XCHoutput', 'a') END call writefile(before, 'XCHinit', 'D') let buf = RunVimInTerminal('-S XCHinit XoneTwoThree', {}) call term_sendkeys(buf, "G") call term_wait(buf, 50) call term_sendkeys(buf, "gg") call term_wait(buf) call WaitForAssert({-> assert_equal(['1'], readfile('XCHoutput')[-1:-1])}) call term_sendkeys(buf, "j") call term_wait(buf) call WaitForAssert({-> assert_equal(['1', '2'], readfile('XCHoutput')[-2:-1])}) call term_sendkeys(buf, "j") call term_wait(buf) call WaitForAssert({-> assert_equal(['1', '2', '3'], readfile('XCHoutput')[-3:-1])}) call StopVimInTerminal(buf) call delete('XCHoutput') endfunc if has('timers') func ExitInsertMode(id) call feedkeys("\<Esc>") endfunc func Test_cursorhold_insert() " depends on timing let g:test_is_flaky = 1 " Need to move the cursor. call feedkeys("ggG", "xt") let g:triggered = 0 au CursorHoldI * let g:triggered += 1 set updatetime=20 call timer_start(200, 'ExitInsertMode') call feedkeys('a', 'x!') sleep 30m call assert_equal(1, g:triggered) unlet g:triggered au! CursorHoldI set updatetime& endfunc func Test_cursorhold_insert_with_timer_interrupt() CheckFeature job " Need to move the cursor. call feedkeys("ggG", "xt") " Confirm the timer invoked in exit_cb of the job doesn't disturb " CursorHoldI event. let g:triggered = 0 au CursorHoldI * let g:triggered += 1 set updatetime=100 call job_start(has('win32') ? 'cmd /c echo:' : 'echo', \ {'exit_cb': {-> timer_start(200, 'ExitInsertMode')}}) call feedkeys('a', 'x!') call assert_equal(1, g:triggered) unlet g:triggered au! CursorHoldI set updatetime& endfunc func Test_cursorhold_insert_ctrl_x() let g:triggered = 0 au CursorHoldI * let g:triggered += 1 set updatetime=20 call timer_start(100, 'ExitInsertMode') " CursorHoldI does not trigger after CTRL-X call feedkeys("a\<C-X>", 'x!') call assert_equal(0, g:triggered) unlet g:triggered au! CursorHoldI set updatetime& endfunc func Test_cursorhold_insert_ctrl_g_U() au CursorHoldI * : set updatetime=20 new call timer_start(100, { -> feedkeys("\<Left>foo\<Esc>", 't') }) call feedkeys("i()\<C-g>U", 'tx!') sleep 200m call assert_equal('(foo)', getline(1)) undo call assert_equal('', getline(1)) bwipe! au! CursorHoldI set updatetime& endfunc func Test_OptionSet_modeline() call test_override('starting', 1) au! OptionSet augroup set_tabstop au OptionSet tabstop call timer_start(1, {-> execute("echo 'Handler called'", "")}) augroup END call writefile(['vim: set ts=7 sw=5 :', 'something'], 'XoptionsetModeline', 'D') set modeline let v:errmsg = '' call assert_fails('split XoptionsetModeline', 'E12:') call assert_equal(7, &ts) call assert_equal('', v:errmsg) augroup set_tabstop au! augroup END bwipe! set ts& call test_override('starting', 0) endfunc endif "has('timers') func Test_bufunload() augroup test_bufunload_group autocmd! autocmd BufUnload * call add(s:li, "bufunload") autocmd BufDelete * call add(s:li, "bufdelete") autocmd BufWipeout * call add(s:li, "bufwipeout") augroup END let s:li = [] new setlocal bufhidden= bunload call assert_equal(["bufunload", "bufdelete"], s:li) let s:li = [] new setlocal bufhidden=delete bunload call assert_equal(["bufunload", "bufdelete"], s:li) let s:li = [] new setlocal bufhidden=unload bwipeout call assert_equal(["bufunload", "bufdelete", "bufwipeout"], s:li) au! test_bufunload_group augroup! test_bufunload_group endfunc " SEGV occurs in older versions. (At least 7.4.2005 or older) func Test_autocmd_bufunload_with_tabnext() tabedit tabfirst augroup test_autocmd_bufunload_with_tabnext_group autocmd! autocmd BufUnload <buffer> tabnext augroup END quit call assert_equal(2, tabpagenr('$')) autocmd! test_autocmd_bufunload_with_tabnext_group augroup! test_autocmd_bufunload_with_tabnext_group tablast quit endfunc func Test_argdelete_in_next() au BufNew,BufEnter,BufLeave,BufWinEnter * argdel call assert_fails('next a b', 'E1156:') au! BufNew,BufEnter,BufLeave,BufWinEnter * endfunc func Test_autocmd_bufwinleave_with_tabfirst() tabedit augroup sample autocmd! autocmd BufWinLeave <buffer> tabfirst augroup END call setline(1, ['a', 'b', 'c']) edit! a.txt tabclose endfunc " SEGV occurs in older versions. (At least 7.4.2321 or older) func Test_autocmd_bufunload_avoiding_SEGV_01() split aa.txt let lastbuf = bufnr('$') augroup test_autocmd_bufunload autocmd! exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!' augroup END call assert_fails('edit bb.txt', 'E937:') autocmd! test_autocmd_bufunload augroup! test_autocmd_bufunload bwipe! aa.txt bwipe! bb.txt endfunc " SEGV occurs in older versions. (At least 7.4.2321 or older) func Test_autocmd_bufunload_avoiding_SEGV_02() setlocal buftype=nowrite let lastbuf = bufnr('$') augroup test_autocmd_bufunload autocmd! exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!' augroup END normal! i1 call assert_fails('edit a.txt', 'E517:') autocmd! test_autocmd_bufunload augroup! test_autocmd_bufunload bwipe! a.txt endfunc func Test_autocmd_dummy_wipeout() " prepare files call writefile([''], 'Xdummywipetest1.txt', 'D') call writefile([''], 'Xdummywipetest2.txt', 'D') augroup test_bufunload_group autocmd! autocmd BufUnload * call add(s:li, "bufunload") autocmd BufDelete * call add(s:li, "bufdelete") autocmd BufWipeout * call add(s:li, "bufwipeout") augroup END let s:li = [] split Xdummywipetest1.txt silent! vimgrep /notmatched/ Xdummywipetest* call assert_equal(["bufunload", "bufwipeout"], s:li) bwipeout au! test_bufunload_group augroup! test_bufunload_group endfunc func Test_win_tab_autocmd() let g:record = [] augroup testing au WinNewPre * call add(g:record, 'WinNewPre') au WinNew * call add(g:record, 'WinNew') au WinClosed * call add(g:record, 'WinClosed') au WinEnter * call add(g:record, 'WinEnter') au WinLeave * call add(g:record, 'WinLeave') au TabNew * call add(g:record, 'TabNew') au TabClosed * call add(g:record, 'TabClosed') au TabEnter * call add(g:record, 'TabEnter') au TabLeave * call add(g:record, 'TabLeave') augroup END split tabnew close close call assert_equal([ \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter', \ 'WinLeave', 'TabLeave', 'WinNewPre', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter', \ 'WinLeave', 'WinClosed', 'WinEnter' \ ], g:record) let g:record = [] tabnew somefile tabnext bwipe somefile call assert_equal([ \ 'WinLeave', 'TabLeave', 'WinNewPre', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', \ 'WinClosed', 'TabClosed' \ ], g:record) let g:record = [] copen help tabnext vnew call assert_equal([ \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter', \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter', \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter' \ ], g:record) augroup testing au! augroup END unlet g:record endfunc func Test_WinNewPre() " Test that the old window layout can be accessed before a new window is created. let g:layouts_pre = [] let g:layouts_post = [] augroup testing au WinNewPre * call add(g:layouts_pre, winlayout()) au WinNew * call add(g:layouts_post, winlayout()) augroup END split call assert_notequal(g:layouts_pre[0], g:layouts_post[0]) split call assert_equal(g:layouts_pre[1], g:layouts_post[0]) call assert_notequal(g:layouts_pre[1], g:layouts_post[1]) tabnew call assert_notequal(g:layouts_pre[2], g:layouts_post[1]) call assert_notequal(g:layouts_pre[2], g:layouts_post[2]) augroup testing au! augroup END unlet g:layouts_pre unlet g:layouts_post " Test modifying window layout during WinNewPre throws. let g:caught = 0 augroup testing au! au WinNewPre * split augroup END try vnew catch let g:caught += 1 endtry augroup testing au! au WinNewPre * tabnew augroup END try vnew catch let g:caught += 1 endtry augroup testing au! au WinNewPre * close augroup END try vnew catch let g:caught += 1 endtry augroup testing au! au WinNewPre * tabclose augroup END try vnew catch let g:caught += 1 endtry call assert_equal(4, g:caught) augroup testing au! augroup END unlet g:caught endfunc func Test_WinResized() CheckRunVimInTerminal let lines =<< trim END set scrolloff=0 call setline(1, ['111', '222']) vnew call setline(1, ['aaa', 'bbb']) new call setline(1, ['foo', 'bar']) let g:resized = 0 au WinResized * let g:resized += 1 func WriteResizedEvent() call writefile([json_encode(v:event)], 'XresizeEvent') endfunc au WinResized * call WriteResizedEvent() END call writefile(lines, 'Xtest_winresized', 'D') let buf = RunVimInTerminal('-S Xtest_winresized', {'rows': 10}) " redraw now to avoid a redraw after the :echo command call term_sendkeys(buf, ":redraw!\<CR>") call TermWait(buf) call term_sendkeys(buf, ":echo g:resized\<CR>") call WaitForAssert({-> assert_match('^0$', term_getline(buf, 10))}, 1000) " increase window height, two windows will be reported call term_sendkeys(buf, "\<C-W>+") call TermWait(buf) call term_sendkeys(buf, ":echo g:resized\<CR>") call WaitForAssert({-> assert_match('^1$', term_getline(buf, 10))}, 1000) let event = readfile('XresizeEvent')[0]->json_decode() call assert_equal({ \ 'windows': [1002, 1001], \ }, event) " increase window width, three windows will be reported call term_sendkeys(buf, "\<C-W>>") call TermWait(buf) call term_sendkeys(buf, ":echo g:resized\<CR>") call WaitForAssert({-> assert_match('^2$', term_getline(buf, 10))}, 1000) let event = readfile('XresizeEvent')[0]->json_decode() call assert_equal({ \ 'windows': [1002, 1001, 1000], \ }, event) call delete('XresizeEvent') call StopVimInTerminal(buf) endfunc func Test_WinScrolled() CheckRunVimInTerminal let lines =<< trim END set nowrap scrolloff=0 for ii in range(1, 18) call setline(ii, repeat(nr2char(96 + ii), ii * 2)) endfor let win_id = win_getid() let g:matched = v:false func WriteScrollEvent() call writefile([json_encode(v:event)], 'XscrollEvent') endfunc execute 'au WinScrolled' win_id 'let g:matched = v:true' let g:scrolled = 0 au WinScrolled * let g:scrolled += 1 au WinScrolled * let g:amatch = str2nr(expand('<amatch>')) au WinScrolled * let g:afile = str2nr(expand('<afile>')) au WinScrolled * call WriteScrollEvent() END call writefile(lines, 'Xtest_winscrolled', 'D') let buf = RunVimInTerminal('-S Xtest_winscrolled', {'rows': 6}) call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^0 ', term_getline(buf, 6))}, 1000) " Scroll left/right in Normal mode. call term_sendkeys(buf, "zlzh:echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000) let event = readfile('XscrollEvent')[0]->json_decode() call assert_equal({ \ 'all': {'leftcol': 1, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1000': {'leftcol': -1, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0} \ }, event) " Scroll up/down in Normal mode. call term_sendkeys(buf, "\<c-e>\<c-y>:echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^4 ', term_getline(buf, 6))}, 1000) let event = readfile('XscrollEvent')[0]->json_decode() call assert_equal({ \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1000': {'leftcol': 0, 'topline': -1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0} \ }, event) " Scroll up/down in Insert mode. call term_sendkeys(buf, "Mi\<c-x>\<c-e>\<Esc>i\<c-x>\<c-y>\<Esc>") call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^6 ', term_getline(buf, 6))}, 1000) let event = readfile('XscrollEvent')[0]->json_decode() call assert_equal({ \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1000': {'leftcol': 0, 'topline': -1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0} \ }, event) " Scroll the window horizontally to focus the last letter of the third line " containing only six characters. Moving to the previous and shorter lines " should trigger another autocommand as Vim has to make them visible. call term_sendkeys(buf, "5zl2k") call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^8 ', term_getline(buf, 6))}, 1000) let event = readfile('XscrollEvent')[0]->json_decode() call assert_equal({ \ 'all': {'leftcol': 5, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1000': {'leftcol': -5, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0} \ }, event) " Ensure the command was triggered for the specified window ID. call term_sendkeys(buf, ":echo g:matched\<CR>") call WaitForAssert({-> assert_match('^v:true ', term_getline(buf, 6))}, 1000) " Ensure the expansion of <amatch> and <afile> matches the window ID. call term_sendkeys(buf, ":echo g:amatch == win_id && g:afile == win_id\<CR>") call WaitForAssert({-> assert_match('^v:true ', term_getline(buf, 6))}, 1000) call delete('XscrollEvent') call StopVimInTerminal(buf) endfunc func Test_WinScrolled_mouse() CheckRunVimInTerminal let lines =<< trim END set nowrap scrolloff=0 set mouse=a term=xterm ttymouse=sgr mousetime=200 clipboard= call setline(1, ['foo']->repeat(32)) split let g:scrolled = 0 au WinScrolled * let g:scrolled += 1 END call writefile(lines, 'Xtest_winscrolled_mouse', 'D') let buf = RunVimInTerminal('-S Xtest_winscrolled_mouse', {'rows': 10}) " With the upper split focused, send a scroll-down event to the unfocused one. call test_setmouse(7, 1) call term_sendkeys(buf, "\<ScrollWheelDown>") call TermWait(buf) call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^1', term_getline(buf, 10))}, 1000) " Again, but this time while we're in insert mode. call term_sendkeys(buf, "i\<ScrollWheelDown>\<Esc>") call TermWait(buf) call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^2', term_getline(buf, 10))}, 1000) call StopVimInTerminal(buf) endfunc func Test_WinScrolled_close_curwin() CheckRunVimInTerminal let lines =<< trim END set nowrap scrolloff=0 call setline(1, ['aaa', 'bbb']) vsplit au WinScrolled * close au VimLeave * call writefile(['123456'], 'Xtestout') END call writefile(lines, 'Xtest_winscrolled_close_curwin', 'D') let buf = RunVimInTerminal('-S Xtest_winscrolled_close_curwin', {'rows': 6}) " This was using freed memory call term_sendkeys(buf, "\<C-E>") call TermWait(buf) call StopVimInTerminal(buf) " check the startup script finished to the end call assert_equal(['123456'], readfile('Xtestout')) call delete('Xtestout') endfunc func Test_WinScrolled_once_only() CheckRunVimInTerminal let lines =<< trim END set cmdheight=2 call setline(1, ['aaa', 'bbb']) let trigger_count = 0 func ShowInfo(id) echo g:trigger_count g:winid winlayout() endfunc vsplit split " use a timer to show the info after a redraw au WinScrolled * let trigger_count += 1 | let winid = expand('<amatch>') | call timer_start(100, 'ShowInfo') wincmd j wincmd l END call writefile(lines, 'Xtest_winscrolled_once', 'D') let buf = RunVimInTerminal('-S Xtest_winscrolled_once', #{rows: 10, cols: 60, statusoff: 2}) call term_sendkeys(buf, "\<C-E>") call VerifyScreenDump(buf, 'Test_winscrolled_once_only_1', {}) call StopVimInTerminal(buf) endfunc " Check that WinScrolled is not triggered immediately when defined and there " are split windows. func Test_WinScrolled_not_when_defined() CheckRunVimInTerminal let lines =<< trim END call setline(1, ['aaa', 'bbb']) echo 'nothing happened' func ShowTriggered(id) echo 'triggered' endfunc END call writefile(lines, 'Xtest_winscrolled_not', 'D') let buf = RunVimInTerminal('-S Xtest_winscrolled_not', #{rows: 10, cols: 60, statusoff: 2}) call term_sendkeys(buf, ":split\<CR>") call TermWait(buf) " use a timer to show the message after redrawing call term_sendkeys(buf, ":au WinScrolled * call timer_start(100, 'ShowTriggered')\<CR>") call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_1', {}) call term_sendkeys(buf, "\<C-E>") call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_2', {}) call StopVimInTerminal(buf) endfunc func Test_WinScrolled_long_wrapped() CheckRunVimInTerminal let lines =<< trim END set scrolloff=0 let height = winheight(0) let width = winwidth(0) let g:scrolled = 0 au WinScrolled * let g:scrolled += 1 call setline(1, repeat('foo', height * width)) call cursor(1, height * width) END call writefile(lines, 'Xtest_winscrolled_long_wrapped', 'D') let buf = RunVimInTerminal('-S Xtest_winscrolled_long_wrapped', {'rows': 6}) call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^0 ', term_getline(buf, 6))}, 1000) call term_sendkeys(buf, 'gj') call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^1 ', term_getline(buf, 6))}, 1000) call term_sendkeys(buf, '0') call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000) call term_sendkeys(buf, '$') call term_sendkeys(buf, ":echo g:scrolled\<CR>") call WaitForAssert({-> assert_match('^3 ', term_getline(buf, 6))}, 1000) call StopVimInTerminal(buf) endfunc func Test_WinScrolled_diff() CheckRunVimInTerminal let lines =<< trim END set diffopt+=foldcolumn:0 call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']) vnew call setline(1, ['d', 'e', 'f', 'g', 'h', 'i']) windo diffthis func WriteScrollEvent() call writefile([json_encode(v:event)], 'XscrollEvent') endfunc au WinScrolled * call WriteScrollEvent() END call writefile(lines, 'Xtest_winscrolled_diff', 'D') let buf = RunVimInTerminal('-S Xtest_winscrolled_diff', {'rows': 8}) call term_sendkeys(buf, "\<C-E>") call WaitForAssert({-> assert_match('^d', term_getline(buf, 3))}, 1000) let event = readfile('XscrollEvent')[0]->json_decode() call assert_equal({ \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1000': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1001': {'leftcol': 0, 'topline': 0, 'topfill': -1, 'width': 0, 'height': 0, 'skipcol': 0} \ }, event) call term_sendkeys(buf, "2\<C-E>") call WaitForAssert({-> assert_match('^f', term_getline(buf, 3))}, 1000) let event = readfile('XscrollEvent')[0]->json_decode() call assert_equal({ \ 'all': {'leftcol': 0, 'topline': 2, 'topfill': 2, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1000': {'leftcol': 0, 'topline': 2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1001': {'leftcol': 0, 'topline': 0, 'topfill': -2, 'width': 0, 'height': 0, 'skipcol': 0} \ }, event) call term_sendkeys(buf, "\<C-E>") call WaitForAssert({-> assert_match('^g', term_getline(buf, 3))}, 1000) let event = readfile('XscrollEvent')[0]->json_decode() call assert_equal({ \ 'all': {'leftcol': 0, 'topline': 2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1000': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1001': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0} \ }, event) call term_sendkeys(buf, "2\<C-Y>") call WaitForAssert({-> assert_match('^e', term_getline(buf, 3))}, 1000) let event = readfile('XscrollEvent')[0]->json_decode() call assert_equal({ \ 'all': {'leftcol': 0, 'topline': 3, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1000': {'leftcol': 0, 'topline': -2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}, \ '1001': {'leftcol': 0, 'topline': -1, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0} \ }, event) call StopVimInTerminal(buf) call delete('XscrollEvent') endfunc func Test_WinClosed() " Test that the pattern is matched against the closed window's ID, and both " <amatch> and <afile> are set to it. new let winid = win_getid() let g:matched = v:false augroup test-WinClosed autocmd! execute 'autocmd WinClosed' winid 'let g:matched = v:true' autocmd WinClosed * let g:amatch = str2nr(expand('<amatch>')) autocmd WinClosed * let g:afile = str2nr(expand('<afile>')) augroup END close call assert_true(g:matched) call assert_equal(winid, g:amatch) call assert_equal(winid, g:afile) " Test that WinClosed is non-recursive. new new call assert_equal(3, winnr('$')) let g:triggered = 0 augroup test-WinClosed autocmd! autocmd WinClosed * let g:triggered += 1 autocmd WinClosed * 2 wincmd c augroup END close call assert_equal(1, winnr('$')) call assert_equal(1, g:triggered) autocmd! test-WinClosed augroup! test-WinClosed unlet g:matched unlet g:amatch unlet g:afile unlet g:triggered endfunc func Test_WinClosed_throws() vnew let bnr = bufnr() call assert_equal(1, bufloaded(bnr)) augroup test-WinClosed autocmd WinClosed * throw 'foo' augroup END try close catch /.*/ endtry call assert_equal(0, bufloaded(bnr)) autocmd! test-WinClosed augroup! test-WinClosed endfunc func Test_WinClosed_throws_with_tabs() tabnew let bnr = bufnr() call assert_equal(1, bufloaded(bnr)) augroup test-WinClosed autocmd WinClosed * throw 'foo' augroup END try close catch /.*/ endtry call assert_equal(0, bufloaded(bnr)) autocmd! test-WinClosed augroup! test-WinClosed endfunc " This used to trigger WinClosed twice for the same window, and the window's " buffer was NULL in the second autocommand. func Test_WinClosed_switch_tab() edit Xa split Xb split Xc tab split new augroup test-WinClosed autocmd WinClosed * tabprev | bwipe! augroup END close " Check that the tabline has been fully removed call assert_equal([1, 1], win_screenpos(0)) autocmd! test-WinClosed augroup! test-WinClosed %bwipe! endfunc " This used to trigger WinClosed twice for the same window, and the window's " buffer was NULL in the second autocommand. func Test_WinClosed_BufUnload_close_other() tabnew let g:tab = tabpagenr() let g:buf = bufnr() new setlocal bufhidden=wipe augroup test-WinClosed autocmd BufUnload * ++once exe g:buf .. 'bwipe!' autocmd WinClosed * call tabpagebuflist(g:tab) augroup END close unlet g:tab unlet g:buf autocmd! test-WinClosed augroup! test-WinClosed %bwipe! endfunc func s:AddAnAutocmd() augroup vimBarTest au BufReadCmd * echo 'hello' augroup END call assert_equal(3, len(split(execute('au vimBarTest'), "\n"))) endfunc func Test_early_bar() " test that a bar is recognized before the {event} call s:AddAnAutocmd() augroup vimBarTest | au! | let done = 77 | augroup END call assert_equal(1, len(split(execute('au vimBarTest'), "\n"))) call assert_equal(77, done) call s:AddAnAutocmd() augroup vimBarTest| au!| let done = 88 | augroup END call assert_equal(1, len(split(execute('au vimBarTest'), "\n"))) call assert_equal(88, done) " test that a bar is recognized after the {event} call s:AddAnAutocmd() augroup vimBarTest| au!BufReadCmd| let done = 99 | augroup END call assert_equal(1, len(split(execute('au vimBarTest'), "\n"))) call assert_equal(99, done) " test that a bar is recognized after the {group} call s:AddAnAutocmd() au! vimBarTest|echo 'hello' call assert_equal(1, len(split(execute('au vimBarTest'), "\n"))) endfunc func RemoveGroup() autocmd! StartOK augroup! StartOK endfunc func Test_augroup_warning() augroup TheWarning au VimEnter * echo 'entering' augroup END call assert_match("TheWarning.*VimEnter", execute('au VimEnter')) redir => res augroup! TheWarning redir END call assert_match("W19:", res) call assert_match("-Deleted-.*VimEnter", execute('au VimEnter')) " check "Another" does not take the pace of the deleted entry augroup Another augroup END call assert_match("-Deleted-.*VimEnter", execute('au VimEnter')) augroup! Another " no warning for postpone aucmd delete augroup StartOK au VimEnter * call RemoveGroup() augroup END call assert_match("StartOK.*VimEnter", execute('au VimEnter')) redir => res doautocmd VimEnter redir END call assert_notmatch("W19:", res) au! VimEnter call assert_fails('augroup!', 'E471:') endfunc func Test_BufReadCmdHelp() " This used to cause access to free memory au BufReadCmd * e +h help au! BufReadCmd endfunc func Test_BufReadCmdHelpJump() " This used to cause access to free memory au BufReadCmd * e +h{ " } to fix highlighting call assert_fails('help', 'E434:') au! BufReadCmd endfunc " BufReadCmd is triggered for a "nofile" buffer. Check all values. func Test_BufReadCmdNofile() for val in ['nofile', \ 'nowrite', \ 'acwrite', \ 'quickfix', \ 'help', \ 'terminal', \ 'prompt', \ 'popup', \ ] new somefile exe 'set buftype=' .. val au BufReadCmd somefile call setline(1, 'triggered') edit call assert_equal('triggered', getline(1)) au! BufReadCmd bwipe! endfor endfunc func Test_augroup_deleted() " This caused a crash before E936 was introduced augroup x call assert_fails('augroup! x', 'E936:') au VimEnter * echo augroup end augroup! x call assert_match("-Deleted-.*VimEnter", execute('au VimEnter')) au! VimEnter endfunc " Tests for autocommands on :close command. " This used to be in test13. func Test_three_windows() " Clean up buffers, because in some cases this function fails. call s:cleanup_buffers() " Write three files and open them, each in a window. " Then go to next window, with autocommand that deletes the previous one. " Do this twice, writing the file. e! Xtestje1 call setline(1, 'testje1') w sp Xtestje2 call setline(1, 'testje2') w sp Xtestje3 call setline(1, 'testje3') w wincmd w au WinLeave Xtestje2 bwipe wincmd w call assert_equal('Xtestje1', expand('%')) au WinLeave Xtestje1 bwipe Xtestje3 close call assert_equal('Xtestje1', expand('%')) " Test deleting the buffer on a Unload event. If this goes wrong there " will be the ATTENTION prompt. e Xtestje1 au! au! BufUnload Xtestje1 bwipe call assert_fails('e Xtestje3', 'E937:') call assert_equal('Xtestje3', expand('%')) e Xtestje2 sp Xtestje1 call assert_fails('e', 'E937:') call assert_equal('Xtestje1', expand('%')) " Test changing buffers in a BufWipeout autocommand. If this goes wrong " there are ml_line errors and/or a Crash. au! only e Xanother e Xtestje1 bwipe Xtestje2 bwipe Xtestje3 au BufWipeout Xtestje1 buf Xtestje1 bwipe call assert_equal('Xanother', expand('%')) only help wincmd w 1quit call assert_equal('Xanother', expand('%')) au! enew call delete('Xtestje1') call delete('Xtestje2') call delete('Xtestje3') endfunc func Test_BufEnter() au! BufEnter au Bufenter * let val = val . '+' let g:val = '' split NewFile call assert_equal('+', g:val) bwipe! call assert_equal('++', g:val) " Also get BufEnter when editing a directory call mkdir('Xbufenterdir', 'D') split Xbufenterdir call assert_equal('+++', g:val) " On MS-Windows we can't edit the directory, make sure we wipe the right " buffer. bwipe! Xbufenterdir au! BufEnter " Editing a "nofile" buffer doesn't read the file but does trigger BufEnter " for historic reasons. Also test other 'buftype' values. for val in ['nofile', \ 'nowrite', \ 'acwrite', \ 'quickfix', \ 'help', \ 'terminal', \ 'prompt', \ 'popup', \ ] new somefile exe 'set buftype=' .. val au BufEnter somefile call setline(1, 'some text') edit call assert_equal('some text', getline(1)) bwipe! au! BufEnter endfor new new autocmd BufEnter * ++once close call assert_fails('close', 'E1312:') au! BufEnter only endfunc " Closing a window might cause an endless loop " E814 for older Vims func Test_autocmd_bufwipe_in_SessLoadPost() edit Xtest tabnew file Xsomething set noswapfile mksession! let content =<< trim [CODE] call test_override('ui_delay', 10) set nocp noswapfile let v:swapchoice = "e" augroup test_autocmd_sessionload autocmd! autocmd SessionLoadPost * exe bufnr("Xsomething") . "bw!" augroup END func WriteErrors() call writefile([execute("messages")], "XerrorsBwipe") endfunc au VimLeave * call WriteErrors() [CODE] call writefile(content, 'Xvimrc', 'D') call system(GetVimCommand('Xvimrc') .. ' --not-a-term --noplugins -S Session.vim -c cq') sleep 100m let errors = join(readfile('XerrorsBwipe')) call assert_match('E814:', errors) set swapfile for file in ['Session.vim', 'XerrorsBwipe'] call delete(file) endfor endfunc " Using :blast and :ball for many events caused a crash, because b_nwindows was " not incremented correctly. func Test_autocmd_blast_badd() let content =<< trim [CODE] au BufNew,BufAdd,BufWinEnter,BufEnter,BufLeave,BufWinLeave,BufUnload,VimEnter foo* blast edit foo1 au BufNew,BufAdd,BufWinEnter,BufEnter,BufLeave,BufWinLeave,BufUnload,VimEnter foo* ball edit foo2 call writefile(['OK'], 'XerrorsBlast') qall [CODE] call writefile(content, 'XblastBall', 'D') call system(GetVimCommand() .. ' --clean -S XblastBall') sleep 100m call assert_match('OK', readfile('XerrorsBlast')->join()) call delete('XerrorsBlast') endfunc " SEGV occurs in older versions. func Test_autocmd_bufwipe_in_SessLoadPost2() tabnew set noswapfile mksession! let content =<< trim [CODE] set nocp noswapfile function! DeleteInactiveBufs() tabfirst let tabblist = [] for i in range(1, tabpagenr(''$'')) call extend(tabblist, tabpagebuflist(i)) endfor for b in range(1, bufnr(''$'')) if bufexists(b) && buflisted(b) && (index(tabblist, b) == -1 || bufname(b) =~# ''^$'') exec ''bwipeout '' . b endif endfor echomsg "SessionLoadPost DONE" endfunction au SessionLoadPost * call DeleteInactiveBufs() func WriteErrors() call writefile([execute("messages")], "XerrorsPost") endfunc au VimLeave * call WriteErrors() [CODE] call writefile(content, 'Xvimrc', 'D') call system(GetVimCommand('Xvimrc') .. ' --not-a-term --noplugins -S Session.vim -c cq') sleep 100m let errors = join(readfile('XerrorsPost')) " This probably only ever matches on unix. call assert_notmatch('Caught deadly signal SEGV', errors) call assert_match('SessionLoadPost DONE', errors) set swapfile for file in ['Session.vim', 'XerrorsPost'] call delete(file) endfor endfunc func Test_empty_doau() doau \| endfunc func s:AutoCommandOptionSet(match) let template = "Option: <%s>, OldVal: <%s>, OldValLocal: <%s>, OldValGlobal: <%s>, NewVal: <%s>, Scope: <%s>, Command: <%s>\n" let item = remove(g:options, 0) let expected = printf(template, item[0], item[1], item[2], item[3], item[4], item[5], item[6]) let actual = printf(template, a:match, v:option_old, v:option_oldlocal, v:option_oldglobal, v:option_new, v:option_type, v:option_command) let g:opt = [expected, actual] "call assert_equal(expected, actual) endfunc func Test_OptionSet() CheckOption autochdir badd test_autocmd.vim call test_override('starting', 1) set nocp au OptionSet * :call s:AutoCommandOptionSet(expand("<amatch>")) " 1: Setting number option" let g:options = [['number', 0, 0, 0, 1, 'global', 'set']] set nu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 2: Setting local number option" let g:options = [['number', 1, 1, '', 0, 'local', 'setlocal']] setlocal nonu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 3: Setting global number option" let g:options = [['number', 1, '', 1, 0, 'global', 'setglobal']] setglobal nonu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 4: Setting local autoindent option" let g:options = [['autoindent', 0, 0, '', 1, 'local', 'setlocal']] setlocal ai call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 5: Setting global autoindent option" let g:options = [['autoindent', 0, '', 0, 1, 'global', 'setglobal']] setglobal ai call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 6: Setting global autoindent option" let g:options = [['autoindent', 1, 1, 1, 0, 'global', 'set']] set ai! call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 6a: Setting global autoindent option" let g:options = [['autoindent', 1, 1, 0, 0, 'global', 'set']] noa setlocal ai noa setglobal noai set ai! call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " Should not print anything, use :noa " 7: don't trigger OptionSet" let g:options = [['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']] noa set nonu call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options) call assert_equal(g:opt[0], g:opt[1]) " 8: Setting several global list and number option" let g:options = [['list', 0, 0, 0, 1, 'global', 'set'], ['number', 0, 0, 0, 1, 'global', 'set']] set list nu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 9: don't trigger OptionSet" let g:options = [['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']] noa set nolist nonu call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options) call assert_equal(g:opt[0], g:opt[1]) " 10: Setting global acd" let g:options = [['autochdir', 0, 0, '', 1, 'local', 'setlocal']] setlocal acd call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 11: Setting global autoread (also sets local value)" let g:options = [['autoread', 0, 0, 0, 1, 'global', 'set']] set ar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 12: Setting local autoread" let g:options = [['autoread', 1, 1, '', 1, 'local', 'setlocal']] setlocal ar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 13: Setting global autoread" let g:options = [['autoread', 1, '', 1, 0, 'global', 'setglobal']] setglobal invar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 14: Setting option backspace through :let" let g:options = [['backspace', '', '', '', 'eol,indent,start', 'global', 'set']] let &bs = "eol,indent,start" call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 15: Setting option backspace through setbufvar()" let g:options = [['backup', 0, 0, '', 1, 'local', 'setlocal']] " try twice, first time, shouldn't trigger because option name is invalid, " second time, it should trigger let bnum = bufnr('%') call assert_fails("call setbufvar(bnum, '&l:bk', 1)", 'E355:') " should trigger, use correct option name call setbufvar(bnum, '&backup', 1) call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 16: Setting number option using setwinvar" let g:options = [['number', 0, 0, '', 1, 'local', 'setlocal']] call setwinvar(0, '&number', 1) call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 17: Setting key option, shouldn't trigger" let g:options = [['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']] setlocal key=blah setlocal key= call assert_equal([['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']], g:options) call assert_equal(g:opt[0], g:opt[1]) " 18a: Setting string global option" let oldval = &backupext let g:options = [['backupext', oldval, oldval, oldval, 'foo', 'global', 'set']] set backupext=foo call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 18b: Resetting string global option" let g:options = [['backupext', 'foo', 'foo', 'foo', oldval, 'global', 'set']] set backupext& call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 18c: Setting global string global option" let g:options = [['backupext', oldval, '', oldval, 'bar', 'global', 'setglobal']] setglobal backupext=bar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 18d: Setting local string global option" " As this is a global option this sets the global value even though " :setlocal is used! noa set backupext& " Reset global and local value (without triggering autocmd) let g:options = [['backupext', oldval, oldval, '', 'baz', 'local', 'setlocal']] setlocal backupext=baz call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 18e: Setting again string global option" noa setglobal backupext=ext_global " Reset global and local value (without triggering autocmd) noa setlocal backupext=ext_local " Sets the global(!) value! let g:options = [['backupext', 'ext_local', 'ext_local', 'ext_local', 'fuu', 'global', 'set']] set backupext=fuu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 19a: Setting string global-local (to buffer) option" let oldval = &tags let g:options = [['tags', oldval, oldval, oldval, 'tagpath', 'global', 'set']] set tags=tagpath call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 19b: Resetting string global-local (to buffer) option" let g:options = [['tags', 'tagpath', 'tagpath', 'tagpath', oldval, 'global', 'set']] set tags& call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 19c: Setting global string global-local (to buffer) option " let g:options = [['tags', oldval, '', oldval, 'tagpath1', 'global', 'setglobal']] setglobal tags=tagpath1 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 19d: Setting local string global-local (to buffer) option" let g:options = [['tags', 'tagpath1', 'tagpath1', '', 'tagpath2', 'local', 'setlocal']] setlocal tags=tagpath2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 19e: Setting again string global-local (to buffer) option" " Note: v:option_old is the old global value for global-local string options " but the old local value for all other kinds of options. noa setglobal tags=tag_global " Reset global and local value (without triggering autocmd) noa setlocal tags=tag_local let g:options = [['tags', 'tag_global', 'tag_local', 'tag_global', 'tagpath', 'global', 'set']] set tags=tagpath call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 19f: Setting string global-local (to buffer) option to an empty string" " Note: v:option_old is the old global value for global-local string options " but the old local value for all other kinds of options. noa set tags=tag_global " Reset global and local value (without triggering autocmd) noa setlocal tags= " empty string let g:options = [['tags', 'tag_global', '', 'tag_global', 'tagpath', 'global', 'set']] set tags=tagpath call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 20a: Setting string local (to buffer) option" let oldval = &spelllang let g:options = [['spelllang', oldval, oldval, oldval, 'elvish,klingon', 'global', 'set']] set spelllang=elvish,klingon call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 20b: Resetting string local (to buffer) option" let g:options = [['spelllang', 'elvish,klingon', 'elvish,klingon', 'elvish,klingon', oldval, 'global', 'set']] set spelllang& call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 20c: Setting global string local (to buffer) option" let g:options = [['spelllang', oldval, '', oldval, 'elvish', 'global', 'setglobal']] setglobal spelllang=elvish call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 20d: Setting local string local (to buffer) option" noa set spelllang& " Reset global and local value (without triggering autocmd) let g:options = [['spelllang', oldval, oldval, '', 'klingon', 'local', 'setlocal']] setlocal spelllang=klingon call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 20e: Setting again string local (to buffer) option" " Note: v:option_old is the old global value for global-local string options " but the old local value for all other kinds of options. noa setglobal spelllang=spellglobal " Reset global and local value (without triggering autocmd) noa setlocal spelllang=spelllocal let g:options = [['spelllang', 'spelllocal', 'spelllocal', 'spellglobal', 'foo', 'global', 'set']] set spelllang=foo call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 21a: Setting string global-local (to window) option" let oldval = &statusline let g:options = [['statusline', oldval, oldval, oldval, 'foo', 'global', 'set']] set statusline=foo call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 21b: Resetting string global-local (to window) option" " Note: v:option_old is the old global value for global-local string options " but the old local value for all other kinds of options. let g:options = [['statusline', 'foo', 'foo', 'foo', oldval, 'global', 'set']] set statusline& call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 21c: Setting global string global-local (to window) option" let g:options = [['statusline', oldval, '', oldval, 'bar', 'global', 'setglobal']] setglobal statusline=bar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 21d: Setting local string global-local (to window) option" noa set statusline& " Reset global and local value (without triggering autocmd) let g:options = [['statusline', oldval, oldval, '', 'baz', 'local', 'setlocal']] setlocal statusline=baz call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 21e: Setting again string global-local (to window) option" " Note: v:option_old is the old global value for global-local string options " but the old local value for all other kinds of options. noa setglobal statusline=bar " Reset global and local value (without triggering autocmd) noa setlocal statusline=baz let g:options = [['statusline', 'bar', 'baz', 'bar', 'foo', 'global', 'set']] set statusline=foo call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 22a: Setting string local (to window) option" let oldval = &foldignore let g:options = [['foldignore', oldval, oldval, oldval, 'fo', 'global', 'set']] set foldignore=fo call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 22b: Resetting string local (to window) option" let g:options = [['foldignore', 'fo', 'fo', 'fo', oldval, 'global', 'set']] set foldignore& call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 22c: Setting global string local (to window) option" let g:options = [['foldignore', oldval, '', oldval, 'bar', 'global', 'setglobal']] setglobal foldignore=bar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 22d: Setting local string local (to window) option" noa set foldignore& " Reset global and local value (without triggering autocmd) let g:options = [['foldignore', oldval, oldval, '', 'baz', 'local', 'setlocal']] setlocal foldignore=baz call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 22e: Setting again string local (to window) option" noa setglobal foldignore=glob " Reset global and local value (without triggering autocmd) noa setlocal foldignore=loc let g:options = [['foldignore', 'loc', 'loc', 'glob', 'fo', 'global', 'set']] set foldignore=fo call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 23a: Setting global number global option" noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd) noa setlocal cmdheight=1 " Sets the global(!) value! let g:options = [['cmdheight', '1', '', '1', '2', 'global', 'setglobal']] setglobal cmdheight=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 23b: Setting local number global option" noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd) noa setlocal cmdheight=1 " Sets the global(!) value! let g:options = [['cmdheight', '1', '1', '', '2', 'local', 'setlocal']] setlocal cmdheight=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 23c: Setting again number global option" noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd) noa setlocal cmdheight=1 " Sets the global(!) value! let g:options = [['cmdheight', '1', '1', '1', '2', 'global', 'set']] set cmdheight=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 23d: Setting again number global option" noa set cmdheight=8 " Reset global and local value (without triggering autocmd) let g:options = [['cmdheight', '8', '8', '8', '2', 'global', 'set']] set cmdheight=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 24a: Setting global number global-local (to buffer) option" noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd) noa setlocal undolevels=1 let g:options = [['undolevels', '8', '', '8', '2', 'global', 'setglobal']] setglobal undolevels=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 24b: Setting local number global-local (to buffer) option" noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd) noa setlocal undolevels=1 let g:options = [['undolevels', '1', '1', '', '2', 'local', 'setlocal']] setlocal undolevels=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 24c: Setting again number global-local (to buffer) option" noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd) noa setlocal undolevels=1 let g:options = [['undolevels', '1', '1', '8', '2', 'global', 'set']] set undolevels=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 24d: Setting again global number global-local (to buffer) option" noa set undolevels=8 " Reset global and local value (without triggering autocmd) let g:options = [['undolevels', '8', '8', '8', '2', 'global', 'set']] set undolevels=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 25a: Setting global number local (to buffer) option" noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd) noa setlocal wrapmargin=1 let g:options = [['wrapmargin', '8', '', '8', '2', 'global', 'setglobal']] setglobal wrapmargin=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 25b: Setting local number local (to buffer) option" noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd) noa setlocal wrapmargin=1 let g:options = [['wrapmargin', '1', '1', '', '2', 'local', 'setlocal']] setlocal wrapmargin=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 25c: Setting again number local (to buffer) option" noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd) noa setlocal wrapmargin=1 let g:options = [['wrapmargin', '1', '1', '8', '2', 'global', 'set']] set wrapmargin=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 25d: Setting again global number local (to buffer) option" noa set wrapmargin=8 " Reset global and local value (without triggering autocmd) let g:options = [['wrapmargin', '8', '8', '8', '2', 'global', 'set']] set wrapmargin=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 26: Setting number global-local (to window) option. " Such option does currently not exist. " 27a: Setting global number local (to window) option" noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd) noa setlocal foldcolumn=1 let g:options = [['foldcolumn', '8', '', '8', '2', 'global', 'setglobal']] setglobal foldcolumn=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 27b: Setting local number local (to window) option" noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd) noa setlocal foldcolumn=1 let g:options = [['foldcolumn', '1', '1', '', '2', 'local', 'setlocal']] setlocal foldcolumn=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 27c: Setting again number local (to window) option" noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd) noa setlocal foldcolumn=1 let g:options = [['foldcolumn', '1', '1', '8', '2', 'global', 'set']] set foldcolumn=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 27d: Setting again global number local (to window) option" noa set foldcolumn=8 " Reset global and local value (without triggering autocmd) let g:options = [['foldcolumn', '8', '8', '8', '2', 'global', 'set']] set foldcolumn=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 28a: Setting global boolean global option" noa setglobal nowrapscan " Reset global and local value (without triggering autocmd) noa setlocal wrapscan " Sets the global(!) value! let g:options = [['wrapscan', '1', '', '1', '0', 'global', 'setglobal']] setglobal nowrapscan call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 28b: Setting local boolean global option" noa setglobal nowrapscan " Reset global and local value (without triggering autocmd) noa setlocal wrapscan " Sets the global(!) value! let g:options = [['wrapscan', '1', '1', '', '0', 'local', 'setlocal']] setlocal nowrapscan call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 28c: Setting again boolean global option" noa setglobal nowrapscan " Reset global and local value (without triggering autocmd) noa setlocal wrapscan " Sets the global(!) value! let g:options = [['wrapscan', '1', '1', '1', '0', 'global', 'set']] set nowrapscan call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 28d: Setting again global boolean global option" noa set nowrapscan " Reset global and local value (without triggering autocmd) let g:options = [['wrapscan', '0', '0', '0', '1', 'global', 'set']] set wrapscan call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 29a: Setting global boolean global-local (to buffer) option" noa setglobal noautoread " Reset global and local value (without triggering autocmd) noa setlocal autoread let g:options = [['autoread', '0', '', '0', '1', 'global', 'setglobal']] setglobal autoread call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 29b: Setting local boolean global-local (to buffer) option" noa setglobal noautoread " Reset global and local value (without triggering autocmd) noa setlocal autoread let g:options = [['autoread', '1', '1', '', '0', 'local', 'setlocal']] setlocal noautoread call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 29c: Setting again boolean global-local (to buffer) option" noa setglobal noautoread " Reset global and local value (without triggering autocmd) noa setlocal autoread let g:options = [['autoread', '1', '1', '0', '1', 'global', 'set']] set autoread call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 29d: Setting again global boolean global-local (to buffer) option" noa set noautoread " Reset global and local value (without triggering autocmd) let g:options = [['autoread', '0', '0', '0', '1', 'global', 'set']] set autoread call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 30a: Setting global boolean local (to buffer) option" noa setglobal nocindent " Reset global and local value (without triggering autocmd) noa setlocal cindent let g:options = [['cindent', '0', '', '0', '1', 'global', 'setglobal']] setglobal cindent call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 30b: Setting local boolean local (to buffer) option" noa setglobal nocindent " Reset global and local value (without triggering autocmd) noa setlocal cindent let g:options = [['cindent', '1', '1', '', '0', 'local', 'setlocal']] setlocal nocindent call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 30c: Setting again boolean local (to buffer) option" noa setglobal nocindent " Reset global and local value (without triggering autocmd) noa setlocal cindent let g:options = [['cindent', '1', '1', '0', '1', 'global', 'set']] set cindent call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 30d: Setting again global boolean local (to buffer) option" noa set nocindent " Reset global and local value (without triggering autocmd) let g:options = [['cindent', '0', '0', '0', '1', 'global', 'set']] set cindent call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 31: Setting boolean global-local (to window) option " Currently no such option exists. " 32a: Setting global boolean local (to window) option" noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd) noa setlocal cursorcolumn let g:options = [['cursorcolumn', '0', '', '0', '1', 'global', 'setglobal']] setglobal cursorcolumn call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 32b: Setting local boolean local (to window) option" noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd) noa setlocal cursorcolumn let g:options = [['cursorcolumn', '1', '1', '', '0', 'local', 'setlocal']] setlocal nocursorcolumn call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 32c: Setting again boolean local (to window) option" noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd) noa setlocal cursorcolumn let g:options = [['cursorcolumn', '1', '1', '0', '1', 'global', 'set']] set cursorcolumn call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 32d: Setting again global boolean local (to window) option" noa set nocursorcolumn " Reset global and local value (without triggering autocmd) let g:options = [['cursorcolumn', '0', '0', '0', '1', 'global', 'set']] set cursorcolumn call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 33: Test autocommands when an option value is converted internally. noa set backspace=1 " Reset global and local value (without triggering autocmd) let g:options = [['backspace', 'indent,eol', 'indent,eol', 'indent,eol', '2', 'global', 'set']] set backspace=2 call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " Cleanup au! OptionSet " set tags& for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'backupext', 'tags', 'spelllang', 'statusline', 'foldignore', 'cmdheight', 'undolevels', 'wrapmargin', 'foldcolumn', 'wrapscan', 'autoread', 'cindent', 'cursorcolumn'] exe printf(":set %s&vim", opt) endfor call test_override('starting', 0) delfunc! AutoCommandOptionSet endfunc func Test_OptionSet_diffmode() call test_override('starting', 1) " 18: Changing an option when entering diff mode new au OptionSet diff :let &l:cul = v:option_new call setline(1, ['buffer 1', 'line2', 'line3', 'line4']) call assert_equal(0, &l:cul) diffthis call assert_equal(1, &l:cul) vnew call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4']) call assert_equal(0, &l:cul) diffthis call assert_equal(1, &l:cul) diffoff call assert_equal(0, &l:cul) call assert_equal(1, getwinvar(2, '&l:cul')) bw! call assert_equal(1, &l:cul) diffoff! call assert_equal(0, &l:cul) call assert_equal(0, getwinvar(1, '&l:cul')) bw! " Cleanup au! OptionSet call test_override('starting', 0) endfunc func Test_OptionSet_diffmode_close() call test_override('starting', 1) " 19: Try to close the current window when entering diff mode " should not segfault new au OptionSet diff close call setline(1, ['buffer 1', 'line2', 'line3', 'line4']) call assert_fails(':diffthis', 'E788:') call assert_equal(1, &diff) vnew call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4']) call assert_fails(':diffthis', 'E788:') call assert_equal(1, &diff) set diffopt-=closeoff bw! call assert_fails(':diffoff!', 'E788:') bw! " Cleanup au! OptionSet call test_override('starting', 0) "delfunc! AutoCommandOptionSet endfunc " Test for Bufleave autocommand that deletes the buffer we are about to edit. func Test_BufleaveWithDelete() new | edit XbufLeave1 augroup test_bufleavewithdelete autocmd! autocmd BufLeave XbufLeave1 bwipe XbufLeave2 augroup END call assert_fails('edit XbufLeave2', 'E143:') call assert_equal('XbufLeave1', bufname('%')) autocmd! test_bufleavewithdelete BufLeave XbufLeave1 augroup! test_bufleavewithdelete new bwipe! XbufLeave1 endfunc " Test for autocommand that changes the buffer list, when doing ":ball". func Test_Acmd_BufAll() enew! %bwipe! call writefile(['Test file Xxx1'], 'Xxx1', 'D') call writefile(['Test file Xxx2'], 'Xxx2', 'D') call writefile(['Test file Xxx3'], 'Xxx3', 'D') " Add three files to the buffer list split Xxx1 close split Xxx2 close split Xxx3 close " Wipe the buffer when the buffer is opened au BufReadPost Xxx2 bwipe call append(0, 'Test file Xxx4') ball call assert_equal(2, winnr('$')) call assert_equal('Xxx1', bufname(winbufnr(winnr('$')))) wincmd t au! BufReadPost %bwipe! enew! | only endfunc " Test for autocommand that changes current buffer on BufEnter event. " Check if modelines are interpreted for the correct buffer. func Test_Acmd_BufEnter() %bwipe! call writefile(['start of test file Xxx1', \ "\<Tab>this is a test", \ 'end of test file Xxx1'], 'Xxx1', 'D') call writefile(['start of test file Xxx2', \ 'vim: set noai :', \ "\<Tab>this is a test", \ 'end of test file Xxx2'], 'Xxx2', 'D') au BufEnter Xxx2 brew set ai modeline modelines=3 edit Xxx1 " edit Xxx2, autocmd will do :brew edit Xxx2 exe "normal G?this is a\<CR>" " Append text with autoindent to this file normal othis should be auto-indented call assert_equal("\<Tab>this should be auto-indented", getline('.')) call assert_equal(3, line('.')) " Remove autocmd and edit Xxx2 again au! BufEnter Xxx2 buf! Xxx2 exe "normal G?this is a\<CR>" " append text without autoindent to Xxx normal othis should be in column 1 call assert_equal("this should be in column 1", getline('.')) call assert_equal(4, line('.')) %bwipe! set ai&vim modeline&vim modelines&vim endfunc " Test for issue #57 " do not move cursor on <c-o> when autoindent is set func Test_ai_CTRL_O() enew! set ai let save_fo = &fo set fo+=r exe "normal o# abcdef\<Esc>2hi\<CR>\<C-O>d0\<Esc>" exe "normal o# abcdef\<Esc>2hi\<C-O>d0\<Esc>" call assert_equal(['# abc', 'def', 'def'], getline(2, 4)) set ai&vim let &fo = save_fo enew! endfunc " Test for autocommand that deletes the current buffer on BufLeave event. " Also test deleting the last buffer, should give a new, empty buffer. func Test_BufLeave_Wipe() %bwipe! let content = ['start of test file Xxx', \ 'this is a test', \ 'end of test file Xxx'] call writefile(content, 'Xxx1', 'D') call writefile(content, 'Xxx2', 'D') au BufLeave Xxx2 bwipe edit Xxx1 split Xxx2 " delete buffer Xxx2, we should be back to Xxx1 bwipe call assert_equal('Xxx1', bufname('%')) call assert_equal(1, winnr('$')) " Create an alternate buffer %write! test.out call assert_equal('test.out', bufname('#')) " delete alternate buffer bwipe test.out call assert_equal('Xxx1', bufname('%')) call assert_equal('', bufname('#')) au BufLeave Xxx1 bwipe " delete current buffer, get an empty one bwipe! call assert_equal(1, line('$')) call assert_equal('', bufname('%')) let g:bufinfo = getbufinfo() call assert_equal(1, len(g:bufinfo)) call delete('test.out') %bwipe au! BufLeave " check that bufinfo doesn't contain a pointer to freed memory call test_garbagecollect_now() endfunc func Test_QuitPre() edit Xfoo let winid = win_getid(winnr()) split Xbar au! QuitPre * let g:afile = expand('<afile>') " Close the other window, <afile> should be correct. exe win_id2win(winid) . 'q' call assert_equal('Xfoo', g:afile) unlet g:afile bwipe Xfoo bwipe Xbar endfunc func Test_Cmdline() au! CmdlineChanged : let g:text = getcmdline() let g:text = 0 call feedkeys(":echom 'hello'\<CR>", 'xt') call assert_equal("echom 'hello'", g:text) au! CmdlineChanged au! CmdlineChanged : let g:entered = expand('<afile>') let g:entered = 0 call feedkeys(":echom 'hello'\<CR>", 'xt') call assert_equal(':', g:entered) au! CmdlineChanged autocmd CmdlineChanged : let g:log += [getcmdline()] let g:log = [] cnoremap <F1> <Cmd>call setcmdline('ls')<CR> call feedkeys(":\<F1>", 'xt') call assert_equal(['ls'], g:log) cunmap <F1> let g:log = [] call feedkeys(":sign \<Tab>\<Tab>\<C-N>\<C-P>\<S-Tab>\<S-Tab>\<Esc>", 'xt') call assert_equal([ \ 's', \ 'si', \ 'sig', \ 'sign', \ 'sign ', \ 'sign define', \ 'sign jump', \ 'sign list', \ 'sign jump', \ 'sign define', \ 'sign ', \ ], g:log) let g:log = [] set wildmenu wildoptions+=pum call feedkeys(":sign \<S-Tab>\<PageUp>\<kPageUp>\<kPageDown>\<PageDown>\<Esc>", 'xt') call assert_equal([ \ 's', \ 'si', \ 'sig', \ 'sign', \ 'sign ', \ 'sign unplace', \ 'sign jump', \ 'sign define', \ 'sign undefine', \ 'sign unplace', \ ], g:log) set wildmenu& wildoptions& let g:log = [] let @r = 'abc' call feedkeys(":0\<C-R>r1\<C-R>\<C-O>r2\<C-R>\<C-R>r3\<Esc>", 'xt') call assert_equal([ \ '0', \ '0a', \ '0ab', \ '0abc', \ '0abc1', \ '0abc1abc', \ '0abc1abc2', \ '0abc1abc2abc', \ '0abc1abc2abc3', \ ], g:log) unlet g:log au! CmdlineChanged au! CmdlineEnter : let g:entered = expand('<afile>') au! CmdlineLeave : let g:left = expand('<afile>') let g:entered = 0 let g:left = 0 call feedkeys(":echo 'hello'\<CR>", 'xt') call assert_equal(':', g:entered) call assert_equal(':', g:left) au! CmdlineEnter au! CmdlineLeave let save_shellslash = &shellslash set noshellslash au! CmdlineEnter / let g:entered = expand('<afile>') au! CmdlineLeave / let g:left = expand('<afile>') let g:entered = 0 let g:left = 0 new call setline(1, 'hello') call feedkeys("/hello\<CR>", 'xt') call assert_equal('/', g:entered) call assert_equal('/', g:left) bwipe! au! CmdlineEnter au! CmdlineLeave let &shellslash = save_shellslash endfunc " Test for BufWritePre autocommand that deletes or unloads the buffer. func Test_BufWritePre() %bwipe au BufWritePre Xxx1 bunload au BufWritePre Xxx2 bwipe call writefile(['start of Xxx1', 'test', 'end of Xxx1'], 'Xxx1', 'D') call writefile(['start of Xxx2', 'test', 'end of Xxx2'], 'Xxx2', 'D') edit Xtest e! Xxx2 bdel Xtest e Xxx1 " write it, will unload it and give an error msg call assert_fails('w', 'E203:') call assert_equal('Xxx2', bufname('%')) edit Xtest e! Xxx2 bwipe Xtest " write it, will delete the buffer and give an error msg call assert_fails('w', 'E203:') call assert_equal('Xxx1', bufname('%')) au! BufWritePre endfunc " Test for BufUnload autocommand that unloads all the other buffers func Test_bufunload_all() let g:test_is_flaky = 1 call writefile(['Test file Xxx1'], 'Xxx1', 'D') call writefile(['Test file Xxx2'], 'Xxx2', 'D') let content =<< trim [CODE] func UnloadAllBufs() let i = 1 while i <= bufnr('$') if i != bufnr('%') && bufloaded(i) exe i . 'bunload' endif let i += 1 endwhile endfunc au BufUnload * call UnloadAllBufs() au VimLeave * call writefile(['Test Finished'], 'Xout') edit Xxx1 split Xxx2 q [CODE] call writefile(content, 'Xbunloadtest', 'D') call delete('Xout') call system(GetVimCommandClean() .. ' -N --not-a-term -S Xbunloadtest') call assert_true(filereadable('Xout')) call delete('Xout') endfunc " Some tests for buffer-local autocommands func Test_buflocal_autocmd() let g:bname = '' edit xx au BufLeave <buffer> let g:bname = expand("%") " here, autocommand for xx should trigger. " but autocommand shall not apply to buffer named <buffer>. edit somefile call assert_equal('xx', g:bname) let g:bname = '' " here, autocommand shall be auto-deleted bwipe xx " autocmd should not trigger edit xx call assert_equal('', g:bname) " autocmd should not trigger edit somefile call assert_equal('', g:bname) enew unlet g:bname endfunc " Test for "*Cmd" autocommands func Test_Cmd_Autocmds() call writefile(['start of Xxx', "\tabc2", 'end of Xxx'], 'Xxx', 'D') enew! au BufReadCmd XtestA 0r Xxx|$del edit XtestA " will read text of Xxd instead call assert_equal('start of Xxx', getline(1)) au BufWriteCmd XtestA call append(line("$"), "write") write " will append a line to the file call assert_equal('write', getline('$')) call assert_fails('read XtestA', 'E484:') " should not read anything call assert_equal('write', getline(4)) " now we have: " 1 start of Xxx " 2 abc2 " 3 end of Xxx " 4 write au FileReadCmd XtestB '[r Xxx 2r XtestB " will read Xxx below line 2 instead call assert_equal('start of Xxx', getline(3)) " now we have: " 1 start of Xxx " 2 abc2 " 3 start of Xxx " 4 abc2 " 5 end of Xxx " 6 end of Xxx " 7 write au FileWriteCmd XtestC '[,']copy $ normal 4GA1 4,5w XtestC " will copy lines 4 and 5 to the end call assert_equal("\tabc21", getline(8)) call assert_fails('r XtestC', 'E484:') " should not read anything call assert_equal("end of Xxx", getline(9)) " now we have: " 1 start of Xxx " 2 abc2 " 3 start of Xxx " 4 abc21 " 5 end of Xxx " 6 end of Xxx " 7 write " 8 abc21 " 9 end of Xxx let g:lines = [] au FileAppendCmd XtestD call extend(g:lines, getline(line("'["), line("']"))) w >>XtestD " will add lines to 'lines' call assert_equal(9, len(g:lines)) call assert_fails('$r XtestD', 'E484:') " should not read anything call assert_equal(9, line('$')) call assert_equal('end of Xxx', getline('$')) au BufReadCmd XtestE 0r Xxx|$del sp XtestE " split window with test.out call assert_equal('end of Xxx', getline(3)) let g:lines = [] exe "normal 2Goasdf\<Esc>\<C-W>\<C-W>" au BufWriteCmd XtestE call extend(g:lines, getline(0, '$')) wall " will write other window to 'lines' call assert_equal(4, len(g:lines), g:lines) call assert_equal('asdf', g:lines[2]) au! BufReadCmd au! BufWriteCmd au! FileReadCmd au! FileWriteCmd au! FileAppendCmd %bwipe! enew! endfunc func s:ReadFile() setl noswapfile nomodified let filename = resolve(expand("<afile>:p")) execute 'read' fnameescape(filename) 1d_ exe 'file' fnameescape(filename) setl buftype=acwrite endfunc func s:WriteFile() let filename = resolve(expand("<afile>:p")) setl buftype= noautocmd execute 'write' fnameescape(filename) setl buftype=acwrite setl nomodified endfunc func Test_BufReadCmd() autocmd BufReadCmd *.test call s:ReadFile() autocmd BufWriteCmd *.test call s:WriteFile() call writefile(['one', 'two', 'three'], 'Xcmd.test', 'D') edit Xcmd.test call assert_match('Xcmd.test" line 1 of 3', execute('file')) normal! Gofour write call assert_equal(['one', 'two', 'three', 'four'], readfile('Xcmd.test')) bwipe! au! BufReadCmd au! BufWriteCmd endfunc func Test_BufWriteCmd() autocmd BufWriteCmd Xbufwritecmd let g:written = 1 new file Xbufwritecmd set buftype=acwrite call mkdir('Xbufwritecmd', 'D') write " BufWriteCmd should be triggered even if a directory has the same name call assert_equal(1, g:written) unlet g:written au! BufWriteCmd bwipe! endfunc func SetChangeMarks(start, end) exe a:start .. 'mark [' exe a:end .. 'mark ]' endfunc " Verify the effects of autocmds on '[ and '] func Test_change_mark_in_autocmds() edit! Xtest call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u\<Esc>", 'xtn') call SetChangeMarks(2, 3) write call assert_equal([1, 4], [line("'["), line("']")]) call SetChangeMarks(2, 3) au BufWritePre * call assert_equal([1, 4], [line("'["), line("']")]) write au! BufWritePre if has('unix') write XtestFilter write >> XtestFilter call SetChangeMarks(2, 3) " Marks are set to the entire range of the write au FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")]) " '[ is adjusted to just before the line that will receive the filtered " data au FilterReadPre * call assert_equal([4, 4], [line("'["), line("']")]) " The filtered data is read into the buffer, and the source lines are " still present, so the range is after the source lines au FilterReadPost * call assert_equal([5, 12], [line("'["), line("']")]) %!cat XtestFilter " After the filtered data is read, the original lines are deleted call assert_equal([1, 8], [line("'["), line("']")]) au! FilterWritePre,FilterReadPre,FilterReadPost undo call SetChangeMarks(1, 4) au FilterWritePre * call assert_equal([2, 3], [line("'["), line("']")]) au FilterReadPre * call assert_equal([3, 3], [line("'["), line("']")]) au FilterReadPost * call assert_equal([4, 11], [line("'["), line("']")]) 2,3!cat XtestFilter call assert_equal([2, 9], [line("'["), line("']")]) au! FilterWritePre,FilterReadPre,FilterReadPost undo call delete('XtestFilter') endif call SetChangeMarks(1, 4) au FileWritePre * call assert_equal([2, 3], [line("'["), line("']")]) 2,3write Xtest2 au! FileWritePre call SetChangeMarks(2, 3) au FileAppendPre * call assert_equal([1, 4], [line("'["), line("']")]) write >> Xtest2 au! FileAppendPre call SetChangeMarks(1, 4) au FileAppendPre * call assert_equal([2, 3], [line("'["), line("']")]) 2,3write >> Xtest2 au! FileAppendPre call SetChangeMarks(1, 1) au FileReadPre * call assert_equal([3, 1], [line("'["), line("']")]) au FileReadPost * call assert_equal([4, 11], [line("'["), line("']")]) 3read Xtest2 au! FileReadPre,FileReadPost undo call SetChangeMarks(4, 4) " When the line is 0, it's adjusted to 1 au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")]) au FileReadPost * call assert_equal([1, 8], [line("'["), line("']")]) 0read Xtest2 au! FileReadPre,FileReadPost undo call SetChangeMarks(4, 4) " When the line is 0, it's adjusted to 1 au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")]) au FileReadPost * call assert_equal([2, 9], [line("'["), line("']")]) 1read Xtest2 au! FileReadPre,FileReadPost undo bwipe! call delete('Xtest') call delete('Xtest2') endfunc func Test_Filter_noshelltemp() CheckExecutable cat enew! call setline(1, ['a', 'b', 'c', 'd']) let shelltemp = &shelltemp set shelltemp let g:filter_au = 0 au FilterWritePre * let g:filter_au += 1 au FilterReadPre * let g:filter_au += 1 au FilterReadPost * let g:filter_au += 1 %!cat call assert_equal(3, g:filter_au) if has('filterpipe') set noshelltemp let g:filter_au = 0 au FilterWritePre * let g:filter_au += 1 au FilterReadPre * let g:filter_au += 1 au FilterReadPost * let g:filter_au += 1 %!cat call assert_equal(0, g:filter_au) endif au! FilterWritePre,FilterReadPre,FilterReadPost let &shelltemp = shelltemp bwipe! endfunc func Test_TextYankPost() enew! call setline(1, ['foo']) let g:event = [] au TextYankPost * let g:event = copy(v:event) call assert_equal({}, v:event) call assert_fails('let v:event = {}', 'E46:') call assert_fails('let v:event.mykey = 0', 'E742:') norm "ayiw call assert_equal( \ #{regcontents: ['foo'], regname: 'a', operator: 'y', \ regtype: 'v', visual: v:false, inclusive: v:true}, \ g:event) norm y_ call assert_equal( \ #{regcontents: ['foo'], regname: '', operator: 'y', regtype: 'V', \ visual: v:false, inclusive: v:false}, \ g:event) norm Vy call assert_equal( \ #{regcontents: ['foo'], regname: '', operator: 'y', regtype: 'V', \ visual: v:true, inclusive: v:true}, \ g:event) call feedkeys("\<C-V>y", 'x') call assert_equal( \ #{regcontents: ['f'], regname: '', operator: 'y', regtype: "\x161", \ visual: v:true, inclusive: v:true}, \ g:event) norm "xciwbar call assert_equal( \ #{regcontents: ['foo'], regname: 'x', operator: 'c', regtype: 'v', \ visual: v:false, inclusive: v:true}, \ g:event) norm "bdiw call assert_equal( \ #{regcontents: ['bar'], regname: 'b', operator: 'd', regtype: 'v', \ visual: v:false, inclusive: v:true}, \ g:event) call setline(1, 'foobar') " exclusive motion norm $"ay0 call assert_equal( \ #{regcontents: ['fooba'], regname: 'a', operator: 'y', regtype: 'v', \ visual: v:false, inclusive: v:false}, \ g:event) " inclusive motion norm 0"ay$ call assert_equal( \ #{regcontents: ['foobar'], regname: 'a', operator: 'y', regtype: 'v', \ visual: v:false, inclusive: v:true}, \ g:event) call assert_equal({}, v:event) if has('clipboard_working') && !has('gui_running') " Test that when the visual selection is automatically copied to clipboard " register a TextYankPost is emitted call setline(1, ['foobar']) let @* = '' set clipboard=autoselect exe "norm! ggviw\<Esc>" call assert_equal( \ #{regcontents: ['foobar'], regname: '*', operator: 'y', \ regtype: 'v', visual: v:true, inclusive: v:false}, \ g:event) let @+ = '' set clipboard=autoselectplus exe "norm! ggviw\<Esc>" call assert_equal( \ #{regcontents: ['foobar'], regname: '+', operator: 'y', \ regtype: 'v', visual: v:true, inclusive: v:false}, \ g:event) set clipboard&vim endif au! TextYankPost unlet g:event bwipe! endfunc func Test_autocommand_all_events() call assert_fails('au * * bwipe', 'E1155:') call assert_fails('au * x bwipe', 'E1155:') call assert_fails('au! * x bwipe', 'E1155:') endfunc func Test_autocmd_user() au User MyEvent let s:res = [expand("<afile>"), expand("<amatch>")] doautocmd User MyEvent call assert_equal(['MyEvent', 'MyEvent'], s:res) au! User unlet s:res endfunc func Test_autocmd_user_clear_group() CheckRunVimInTerminal let lines =<< trim END autocmd! User for i in range(1, 999) exe 'autocmd User ' .. 'Foo' .. i .. ' bar' endfor au CmdlineLeave : call timer_start(0, {-> execute('autocmd! User')}) END call writefile(lines, 'XautoUser', 'D') let buf = RunVimInTerminal('-S XautoUser', {'rows': 10}) " this was using freed memory call term_sendkeys(buf, ":autocmd User\<CR>") call TermWait(buf, 50) call term_sendkeys(buf, "G") call StopVimInTerminal(buf) endfunc func Test_autocmd_CmdlineLeave_unlet() CheckRunVimInTerminal let lines =<< trim END for i in range(1, 999) exe 'let g:var' .. i '=' i endfor au CmdlineLeave : call timer_start(0, {-> execute('unlet g:var990')}) END call writefile(lines, 'XleaveUnlet', 'D') let buf = RunVimInTerminal('-S XleaveUnlet', {'rows': 10}) " this was using freed memory call term_sendkeys(buf, ":let g:\<CR>") call TermWait(buf, 50) call term_sendkeys(buf, "G") call TermWait(buf, 50) call term_sendkeys(buf, "\<CR>") " for the hit-enter prompt call StopVimInTerminal(buf) endfunc function s:Before_test_dirchanged() augroup test_dirchanged autocmd! augroup END let s:li = [] let s:dir_this = getcwd() let s:dir_foo = s:dir_this . '/Xfoo' call mkdir(s:dir_foo) let s:dir_bar = s:dir_this . '/Xbar' call mkdir(s:dir_bar) endfunc function s:After_test_dirchanged() call chdir(s:dir_this) call delete(s:dir_foo, 'd') call delete(s:dir_bar, 'd') augroup test_dirchanged autocmd! augroup END endfunc function Test_dirchanged_global() call s:Before_test_dirchanged() autocmd test_dirchanged DirChangedPre global call add(s:li, expand("<amatch>") .. " pre cd " .. v:event.directory) autocmd test_dirchanged DirChanged global call add(s:li, "cd:") autocmd test_dirchanged DirChanged global call add(s:li, expand("<afile>")) call chdir(s:dir_foo) let expected = ["global pre cd " .. s:dir_foo, "cd:", s:dir_foo] call assert_equal(expected, s:li) call chdir(s:dir_foo) call assert_equal(expected, s:li) exe 'lcd ' .. fnameescape(s:dir_bar) call assert_equal(expected, s:li) exe 'cd ' .. s:dir_foo exe 'cd ' .. s:dir_bar autocmd! test_dirchanged DirChanged global let g:result = expand("<afile>") cd - call assert_equal(s:dir_foo, substitute(g:result, '\\', '/', 'g')) call s:After_test_dirchanged() endfunc function Test_dirchanged_local() call s:Before_test_dirchanged() autocmd test_dirchanged DirChanged window call add(s:li, "lcd:") autocmd test_dirchanged DirChanged window call add(s:li, expand("<afile>")) call chdir(s:dir_foo) call assert_equal([], s:li) exe 'lcd ' .. fnameescape(s:dir_bar) call assert_equal(["lcd:", s:dir_bar], s:li) exe 'lcd ' .. fnameescape(s:dir_bar) call assert_equal(["lcd:", s:dir_bar], s:li) call s:After_test_dirchanged() endfunc function Test_dirchanged_auto() CheckOption autochdir call s:Before_test_dirchanged() call test_autochdir() autocmd test_dirchanged DirChangedPre auto call add(s:li, "pre cd " .. v:event.directory) autocmd test_dirchanged DirChanged auto call add(s:li, "auto:") autocmd test_dirchanged DirChanged auto call add(s:li, expand("<afile>")) set acd cd .. call assert_equal([], s:li) exe 'edit ' . s:dir_foo . '/Xautofile' call assert_equal(s:dir_foo, getcwd()) let expected = ["pre cd " .. s:dir_foo, "auto:", s:dir_foo] call assert_equal(expected, s:li) set noacd bwipe! call s:After_test_dirchanged() endfunc " Test TextChangedI and TextChangedP func Test_ChangedP() new call setline(1, ['foo', 'bar', 'foobar']) call test_override("char_avail", 1) set complete=. completeopt=menuone func! TextChangedAutocmd(char) let g:autocmd .= a:char endfunc " TextChanged will not be triggered, only check that it isn't. au! TextChanged <buffer> :call TextChangedAutocmd('N') au! TextChangedI <buffer> :call TextChangedAutocmd('I') au! TextChangedP <buffer> :call TextChangedAutocmd('P') call cursor(3, 1) let g:autocmd = '' call feedkeys("o\<esc>", 'tnix') call assert_equal('I', g:autocmd) let g:autocmd = '' call feedkeys("Sf", 'tnix') call assert_equal('II', g:autocmd) let g:autocmd = '' call feedkeys("Sf\<C-N>", 'tnix') call assert_equal('IIP', g:autocmd) let g:autocmd = '' call feedkeys("Sf\<C-N>\<C-N>", 'tnix') call assert_equal('IIPP', g:autocmd) let g:autocmd = '' call feedkeys("Sf\<C-N>\<C-N>\<C-N>", 'tnix') call assert_equal('IIPPP', g:autocmd) let g:autocmd = '' call feedkeys("Sf\<C-N>\<C-N>\<C-N>\<C-N>", 'tnix') call assert_equal('IIPPPP', g:autocmd) call assert_equal(['foo', 'bar', 'foobar', 'foo'], getline(1, '$')) " TODO: how should it handle completeopt=noinsert,noselect? " CleanUp call test_override("char_avail", 0) au! TextChanged au! TextChangedI au! TextChangedP delfu TextChangedAutocmd unlet! g:autocmd set complete&vim completeopt&vim bw! endfunc let g:setline_handled = v:false func SetLineOne() if !g:setline_handled call setline(1, "(x)") let g:setline_handled = v:true endif endfunc func Test_TextChangedI_with_setline() new call test_override('char_avail', 1) autocmd TextChangedI <buffer> call SetLineOne() call feedkeys("i(\<CR>\<Esc>", 'tx') call assert_equal('(', getline(1)) call assert_equal('x)', getline(2)) undo call assert_equal('', getline(1)) call assert_equal('', getline(2)) call test_override('char_avail', 0) bwipe! endfunc func Test_TextChanged_with_norm() " For unknown reason this fails on MS-Windows CheckNotMSWindows CheckFeature terminal let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3}) call assert_equal('running', term_getstatus(buf)) call term_sendkeys(buf, ":let g:a=0\<cr>") call term_wait(buf, 50) call term_sendkeys(buf, ":au! TextChanged * :let g:a+=1\<cr>") call term_wait(buf, 50) call term_sendkeys(buf, ":norm! ia\<cr>") call term_wait(buf, 50) call term_sendkeys(buf, ":echo g:a\<cr>") call term_wait(buf, 50) call WaitForAssert({-> assert_match('^1.*$', term_getline(buf, 3))}) bwipe! endfunc func Test_Changed_FirstTime() CheckFeature terminal CheckNotGui " Starting a terminal to run Vim is always considered flaky. let g:test_is_flaky = 1 " Prepare file for TextChanged event. call writefile([''], 'Xchanged.txt', 'D') let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3}) call assert_equal('running', term_getstatus(buf)) " Wait for the ruler (in the status line) to be shown. " In ConPTY, there is additional character which is drawn up to the width of " the screen. if has('conpty') call WaitForAssert({-> assert_match('\<All.*$', term_getline(buf, 3))}) else call WaitForAssert({-> assert_match('\<All$', term_getline(buf, 3))}) endif " It's only adding autocmd, so that no event occurs. call term_sendkeys(buf, ":au! TextChanged <buffer> call writefile(['No'], 'Xchanged.txt')\<cr>") call term_sendkeys(buf, "\<C-\\>\<C-N>:qa!\<cr>") call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))}) call assert_equal([''], readfile('Xchanged.txt')) " clean up bwipe! endfunc func Test_autocmd_nested() let g:did_nested = 0 augroup Testing au WinNew * edit somefile au BufNew * let g:did_nested = 1 augroup END split call assert_equal(0, g:did_nested) close bwipe! somefile " old nested argument still works augroup Testing au! au WinNew * nested edit somefile au BufNew * let g:did_nested = 1 augroup END split call assert_equal(1, g:did_nested) close bwipe! somefile " New ++nested argument works augroup Testing au! au WinNew * ++nested edit somefile au BufNew * let g:did_nested = 1 augroup END split call assert_equal(1, g:did_nested) close bwipe! somefile " nested without ++ does not work in Vim9 script call assert_fails('vim9cmd au WinNew * nested echo fails', 'E1078:') augroup Testing au! augroup END call assert_fails('au WinNew * ++nested ++nested echo bad', 'E983:') call assert_fails('au WinNew * nested nested echo bad', 'E983:') endfunc func Test_autocmd_nested_cursor_invalid() set laststatus=0 copen cclose call setline(1, ['foo', 'bar', 'baz']) 3 augroup nested_inv autocmd User foo ++nested copen autocmd BufAdd * let &laststatus = 2 - &laststatus augroup END doautocmd User foo augroup nested_inv au! augroup END set laststatus& cclose bwipe! endfunc func Test_autocmd_nested_keeps_cursor_pos() enew call setline(1, 'foo') autocmd User foo ++nested normal! $a autocmd InsertLeave * : doautocmd User foo call assert_equal([0, 1, 3, 0], getpos('.')) bwipe! endfunc func Test_autocmd_nested_switch_window() " run this in a separate Vim so that SafeState works CheckRunVimInTerminal let lines =<< trim END vim9script ['()']->writefile('Xautofile') autocmd VimEnter * ++nested edit Xautofile | split autocmd BufReadPost * autocmd SafeState * ++once foldclosed('.') autocmd WinEnter * matchadd('ErrorMsg', 'pat') END call writefile(lines, 'Xautoscript', 'D') let buf = RunVimInTerminal('-S Xautoscript', {'rows': 10}) call VerifyScreenDump(buf, 'Test_autocmd_nested_switch', {}) call StopVimInTerminal(buf) call delete('Xautofile') endfunc func Test_autocmd_once() " Without ++once WinNew triggers twice let g:did_split = 0 augroup Testing au WinNew * let g:did_split += 1 augroup END split split call assert_equal(2, g:did_split) call assert_true(exists('#WinNew')) close close " With ++once WinNew triggers once let g:did_split = 0 augroup Testing au! au WinNew * ++once let g:did_split += 1 augroup END split split call assert_equal(1, g:did_split) call assert_false(exists('#WinNew')) close close call assert_fails('au WinNew * ++once ++once echo bad', 'E983:') endfunc func Test_autocmd_bufreadpre() new let b:bufreadpre = 1 call append(0, range(1000)) w! XAutocmdBufReadPre.txt autocmd BufReadPre <buffer> :let b:bufreadpre += 1 norm! 500gg sp norm! 1000gg wincmd p let g:wsv1 = winsaveview() wincmd p let g:wsv2 = winsaveview() " triggers BufReadPre, should not move the cursor in either window " The topline may change one line in a large window. edit call assert_inrange(g:wsv2.topline - 1, g:wsv2.topline + 1, winsaveview().topline) call assert_equal(g:wsv2.lnum, winsaveview().lnum) call assert_equal(2, b:bufreadpre) wincmd p call assert_equal(g:wsv1.topline, winsaveview().topline) call assert_equal(g:wsv1.lnum, winsaveview().lnum) call assert_equal(2, b:bufreadpre) " Now set the cursor position in an BufReadPre autocommand " (even though the position will be invalid, this should make Vim reset the " cursor position in the other window. wincmd p set cpo+=g " won't do anything, but try to set the cursor on an invalid lnum autocmd BufReadPre <buffer> :norm! 70gg " triggers BufReadPre, should not move the cursor in either window e call assert_equal(1, winsaveview().topline) call assert_equal(1, winsaveview().lnum) call assert_equal(3, b:bufreadpre) wincmd p call assert_equal(g:wsv1.topline, winsaveview().topline) call assert_equal(g:wsv1.lnum, winsaveview().lnum) call assert_equal(3, b:bufreadpre) close close call delete('XAutocmdBufReadPre.txt') set cpo-=g endfunc " FileChangedShell tested in test_filechanged.vim " Tests for the following autocommands: " - FileWritePre writing a compressed file " - FileReadPost reading a compressed file " - BufNewFile reading a file template " - BufReadPre decompressing the file to be read " - FilterReadPre substituting characters in the temp file " - FilterReadPost substituting characters after filtering " - FileReadPre set options for decompression " - FileReadPost decompress the file func Test_ReadWrite_Autocmds() " Run this test only on Unix-like systems and if gzip is available CheckUnix CheckExecutable gzip " Make $GZIP empty, "-v" would cause trouble. let $GZIP = "" " Use a FileChangedShell autocommand to avoid a prompt for 'Xtestfile.gz' " being modified outside of Vim (noticed on Solaris). au FileChangedShell * echo 'caught FileChangedShell' " Test for the FileReadPost, FileWritePre and FileWritePost autocmds augroup Test1 au! au FileWritePre *.gz '[,']!gzip au FileWritePost *.gz undo au FileReadPost *.gz '[,']!gzip -d augroup END new set bin call append(0, [ \ 'line 2 Abcdefghijklmnopqrstuvwxyz', \ 'line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 4 Abcdefghijklmnopqrstuvwxyz', \ 'line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 6 Abcdefghijklmnopqrstuvwxyz', \ 'line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 8 Abcdefghijklmnopqrstuvwxyz', \ 'line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 10 Abcdefghijklmnopqrstuvwxyz' \ ]) 1,9write! Xtestfile.gz enew! | close new " Read and decompress the testfile 0read Xtestfile.gz call assert_equal([ \ 'line 2 Abcdefghijklmnopqrstuvwxyz', \ 'line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 4 Abcdefghijklmnopqrstuvwxyz', \ 'line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 6 Abcdefghijklmnopqrstuvwxyz', \ 'line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 8 Abcdefghijklmnopqrstuvwxyz', \ 'line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 10 Abcdefghijklmnopqrstuvwxyz' \ ], getline(1, 9)) enew! | close augroup Test1 au! augroup END " Test for the FileAppendPre and FileAppendPost autocmds augroup Test2 au! au BufNewFile *.c read Xtest.c au FileAppendPre *.out '[,']s/new/NEW/ au FileAppendPost *.out !cat Xtest.c >> test.out augroup END call writefile(['/*', ' * Here is a new .c file', ' */'], 'Xtest.c', 'D') new foo.c " should load Xtest.c call assert_equal(['/*', ' * Here is a new .c file', ' */'], getline(2, 4)) w! >> test.out " append it to the output file let contents = readfile('test.out') call assert_equal(' * Here is a NEW .c file', contents[2]) call assert_equal(' * Here is a new .c file', contents[5]) call delete('test.out') enew! | close augroup Test2 au! augroup END " Test for the BufReadPre and BufReadPost autocmds augroup Test3 au! " setup autocommands to decompress before reading and re-compress " afterwards au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand("<afile>")) au BufReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>")) au BufReadPost *.gz call rename(expand("<afile>"), expand("<afile>:r")) au BufReadPost *.gz exe '!gzip ' . shellescape(expand("<afile>:r")) augroup END e! Xtestfile.gz " Edit compressed file call assert_equal([ \ 'line 2 Abcdefghijklmnopqrstuvwxyz', \ 'line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 4 Abcdefghijklmnopqrstuvwxyz', \ 'line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 6 Abcdefghijklmnopqrstuvwxyz', \ 'line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 8 Abcdefghijklmnopqrstuvwxyz', \ 'line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 10 Abcdefghijklmnopqrstuvwxyz' \ ], getline(1, 9)) w! >> test.out " Append it to the output file augroup Test3 au! augroup END " Test for the FilterReadPre and FilterReadPost autocmds. set shelltemp " need temp files here augroup Test4 au! au FilterReadPre *.out call rename(expand("<afile>"), expand("<afile>") . ".t") au FilterReadPre *.out exe 'silent !sed s/e/E/ ' . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>")) au FilterReadPre *.out exe 'silent !rm ' . shellescape(expand("<afile>")) . '.t' au FilterReadPost *.out '[,']s/x/X/g augroup END e! test.out " Edit the output file 1,$!cat call assert_equal([ \ 'linE 2 AbcdefghijklmnopqrstuvwXyz', \ 'linE 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', \ 'linE 4 AbcdefghijklmnopqrstuvwXyz', \ 'linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', \ 'linE 6 AbcdefghijklmnopqrstuvwXyz', \ 'linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', \ 'linE 8 AbcdefghijklmnopqrstuvwXyz', \ 'linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', \ 'linE 10 AbcdefghijklmnopqrstuvwXyz' \ ], getline(1, 9)) call assert_equal([ \ 'line 2 Abcdefghijklmnopqrstuvwxyz', \ 'line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 4 Abcdefghijklmnopqrstuvwxyz', \ 'line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 6 Abcdefghijklmnopqrstuvwxyz', \ 'line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 8 Abcdefghijklmnopqrstuvwxyz', \ 'line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 10 Abcdefghijklmnopqrstuvwxyz' \ ], readfile('test.out')) augroup Test4 au! augroup END set shelltemp&vim " Test for the FileReadPre and FileReadPost autocmds. augroup Test5 au! au FileReadPre *.gz exe 'silent !gzip -d ' . shellescape(expand("<afile>")) au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>")) au FileReadPost *.gz '[,']s/l/L/ augroup END new 0r Xtestfile.gz " Read compressed file call assert_equal([ \ 'Line 2 Abcdefghijklmnopqrstuvwxyz', \ 'Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'Line 4 Abcdefghijklmnopqrstuvwxyz', \ 'Line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'Line 6 Abcdefghijklmnopqrstuvwxyz', \ 'Line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'Line 8 Abcdefghijklmnopqrstuvwxyz', \ 'Line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'Line 10 Abcdefghijklmnopqrstuvwxyz' \ ], getline(1, 9)) call assert_equal([ \ 'line 2 Abcdefghijklmnopqrstuvwxyz', \ 'line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 4 Abcdefghijklmnopqrstuvwxyz', \ 'line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 6 Abcdefghijklmnopqrstuvwxyz', \ 'line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 8 Abcdefghijklmnopqrstuvwxyz', \ 'line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', \ 'line 10 Abcdefghijklmnopqrstuvwxyz' \ ], readfile('Xtestfile.gz')) augroup Test5 au! augroup END au! FileChangedShell call delete('Xtestfile.gz') call delete('test.out') endfunc func Test_throw_in_BufWritePre() new call setline(1, ['one', 'two', 'three']) call assert_false(filereadable('Xthefile')) augroup throwing au BufWritePre X* throw 'do not write' augroup END try w Xthefile catch let caught = 1 endtry call assert_equal(1, caught) call assert_false(filereadable('Xthefile')) bwipe! au! throwing endfunc func Test_autocmd_in_try_block() call mkdir('Xintrydir', 'R') au BufEnter * let g:fname = expand('%') try edit Xintrydir/ endtry call assert_match('Xintrydir', g:fname) unlet g:fname au! BufEnter endfunc func Test_autocmd_SafeState() CheckRunVimInTerminal let lines =<< trim END let g:safe = 0 let g:again = '' au SafeState * let g:safe += 1 au SafeStateAgain * let g:again ..= 'x' func CallTimer() call timer_start(10, {id -> execute('let g:again ..= "t"')}) endfunc END call writefile(lines, 'XSafeState', 'D') let buf = RunVimInTerminal('-S XSafeState', #{rows: 6}) " Sometimes we loop to handle a K_IGNORE, SafeState may be triggered once or " more often. call term_sendkeys(buf, ":echo g:safe\<CR>") call WaitForAssert({-> assert_match('^\d ', term_getline(buf, 6))}, 1000) " SafeStateAgain should be invoked at least three times call term_sendkeys(buf, ":echo g:again\<CR>") call WaitForAssert({-> assert_match('^xxx', term_getline(buf, 6))}, 1000) call term_sendkeys(buf, ":let g:again = ''\<CR>:call CallTimer()\<CR>") call TermWait(buf, 50) call term_sendkeys(buf, ":\<CR>") call TermWait(buf, 50) call term_sendkeys(buf, ":echo g:again\<CR>") call WaitForAssert({-> assert_match('xtx', term_getline(buf, 6))}, 1000) call StopVimInTerminal(buf) endfunc func Test_autocmd_CmdWinEnter() CheckRunVimInTerminal let lines =<< trim END augroup vimHints | au! | augroup END let b:dummy_var = 'This is a dummy' autocmd CmdWinEnter * quit let winnr = winnr('$') END let filename = 'XCmdWinEnter' call writefile(lines, filename) let buf = RunVimInTerminal('-S '.filename, #{rows: 6}) call term_sendkeys(buf, "q:") call TermWait(buf) call term_sendkeys(buf, ":echo b:dummy_var\<cr>") call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 2000) call term_sendkeys(buf, ":echo &buftype\<cr>") call WaitForAssert({-> assert_notmatch('^nofile', term_getline(buf, 6))}, 1000) call term_sendkeys(buf, ":echo winnr\<cr>") call WaitForAssert({-> assert_match('^1', term_getline(buf, 6))}, 1000) " clean up call StopVimInTerminal(buf) call delete(filename) endfunc func Test_autocmd_was_using_freed_memory() CheckFeature quickfix pedit xx n x augroup winenter au WinEnter * if winnr('$') > 2 | quit | endif augroup END split augroup winenter au! WinEnter augroup END bwipe xx bwipe x pclose endfunc func Test_BufWrite_lockmarks() let g:test_is_flaky = 1 edit! Xtest call setline(1, ['a', 'b', 'c', 'd']) " :lockmarks preserves the marks call SetChangeMarks(2, 3) lockmarks write call assert_equal([2, 3], [line("'["), line("']")]) " *WritePre autocmds get the correct line range, but lockmarks preserves the " original values for the user augroup lockmarks au! au BufWritePre,FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")]) au FileWritePre * call assert_equal([3, 4], [line("'["), line("']")]) augroup END lockmarks write call assert_equal([2, 3], [line("'["), line("']")]) if executable('cat') lockmarks %!cat call assert_equal([2, 3], [line("'["), line("']")]) endif lockmarks 3,4write Xtest2 call assert_equal([2, 3], [line("'["), line("']")]) au! lockmarks augroup! lockmarks call delete('Xtest') call delete('Xtest2') endfunc func Test_FileType_spell() if !isdirectory('/tmp') throw "Skipped: requires /tmp directory" endif " this was crashing with an invalid free() setglobal spellfile=/tmp/en.utf-8.add augroup crash autocmd! autocmd BufNewFile,BufReadPost crashfile setf somefiletype autocmd BufNewFile,BufReadPost crashfile set ft=anotherfiletype autocmd FileType anotherfiletype setlocal spell augroup END func! NoCrash() abort edit /tmp/crashfile endfunc call NoCrash() au! crash setglobal spellfile= endfunc " this was wiping out the current buffer and using freed memory func Test_SpellFileMissing_bwipe() next 0 au SpellFileMissing 0 bwipe call assert_fails('set spell spelllang=0', 'E937:') au! SpellFileMissing set nospell spelllang=en bwipe endfunc " Test closing a window or editing another buffer from a FileChangedRO handler " in a readonly buffer func Test_FileChangedRO_winclose() call test_override('ui_delay', 10) augroup FileChangedROTest au! autocmd FileChangedRO * quit augroup END new set readonly call assert_fails('normal i', 'E788:') close augroup! FileChangedROTest augroup FileChangedROTest au! autocmd FileChangedRO * edit Xrofile augroup END new set readonly call assert_fails('normal i', 'E788:') close augroup! FileChangedROTest call test_override('ALL', 0) endfunc func LogACmd() call add(g:logged, line('$')) endfunc func Test_TermChanged() CheckNotGui enew! tabnew call setline(1, ['a', 'b', 'c', 'd']) $ au TermChanged * call LogACmd() let g:logged = [] let term_save = &term set term=xterm call assert_equal([1, 4], g:logged) au! TermChanged let &term = term_save bwipe! endfunc " Test for FileReadCmd autocmd func Test_autocmd_FileReadCmd() func ReadFileCmd() call append(line('$'), "v:cmdarg = " .. v:cmdarg) endfunc augroup FileReadCmdTest au! au FileReadCmd Xtest call ReadFileCmd() augroup END new read ++bin Xtest read ++nobin Xtest read ++edit Xtest read ++bad=keep Xtest read ++bad=drop Xtest read ++bad=- Xtest read ++ff=unix Xtest read ++ff=dos Xtest read ++ff=mac Xtest read ++enc=utf-8 Xtest call assert_equal(['', \ 'v:cmdarg = ++bin', \ 'v:cmdarg = ++nobin', \ 'v:cmdarg = ++edit', \ 'v:cmdarg = ++bad=keep', \ 'v:cmdarg = ++bad=drop', \ 'v:cmdarg = ++bad=-', \ 'v:cmdarg = ++ff=unix', \ 'v:cmdarg = ++ff=dos', \ 'v:cmdarg = ++ff=mac', \ 'v:cmdarg = ++enc=utf-8'], getline(1, '$')) bwipe! augroup FileReadCmdTest au! augroup END delfunc ReadFileCmd endfunc " Test for passing invalid arguments to autocmd func Test_autocmd_invalid_args() " Additional character after * for event call assert_fails('autocmd *a Xinvfile set ff=unix', 'E215:') augroup Test augroup END " Invalid autocmd event call assert_fails('autocmd Bufabc Xinvfile set ft=vim', 'E216:') " Invalid autocmd event in a autocmd group call assert_fails('autocmd Test Bufabc Xinvfile set ft=vim', 'E216:') augroup! Test " Execute all autocmds call assert_fails('doautocmd * BufEnter', 'E217:') call assert_fails('augroup! x1a2b3', 'E367:') call assert_fails('autocmd BufNew <buffer=999> pwd', 'E680:') call assert_fails('autocmd BufNew \) set ff=unix', 'E55:') endfunc " Test for deep nesting of autocmds func Test_autocmd_deep_nesting() autocmd BufEnter Xdeepfile doautocmd BufEnter Xdeepfile call assert_fails('doautocmd BufEnter Xdeepfile', 'E218:') autocmd! BufEnter Xdeepfile endfunc " Tests for SigUSR1 autocmd event, which is only available on posix systems. func Test_autocmd_sigusr1() CheckUnix " FIXME: should this work on MacOS M1? CheckNotMacM1 CheckExecutable /bin/kill let g:sigusr1_passed = 0 au SigUSR1 * let g:sigusr1_passed = 1 call system('/bin/kill -s usr1 ' . getpid()) call WaitForAssert({-> assert_true(g:sigusr1_passed)}) au! SigUSR1 unlet g:sigusr1_passed endfunc " Test for BufReadPre autocmd deleting the file func Test_BufReadPre_delfile() augroup TestAuCmd au! autocmd BufReadPre XbufreadPre call delete('XbufreadPre') augroup END call writefile([], 'XbufreadPre', 'D') call assert_fails('new XbufreadPre', 'E200:') call assert_equal('XbufreadPre', @%) call assert_equal(1, &readonly) augroup TestAuCmd au! augroup END close! endfunc " Test for BufReadPre autocmd changing the current buffer func Test_BufReadPre_changebuf() augroup TestAuCmd au! autocmd BufReadPre Xchangebuf edit Xsomeotherfile augroup END call writefile([], 'Xchangebuf', 'D') call assert_fails('new Xchangebuf', 'E201:') call assert_equal('Xsomeotherfile', @%) call assert_equal(1, &readonly) augroup TestAuCmd au! augroup END close! endfunc " Test for BufWipeouti autocmd changing the current buffer when reading a file " in an empty buffer with 'f' flag in 'cpo' func Test_BufDelete_changebuf() new augroup TestAuCmd au! autocmd BufWipeout * let bufnr = bufadd('somefile') | exe "b " .. bufnr augroup END let save_cpo = &cpo set cpo+=f call assert_fails('r Xchangebuf', ['E812:', 'E484:']) call assert_equal('somefile', @%) let &cpo = save_cpo augroup TestAuCmd au! augroup END close! endfunc " Test for the temporary internal window used to execute autocmds func Test_autocmd_window() %bw! edit one.txt tabnew two.txt vnew three.txt tabnew four.txt tabprevious let g:blist = [] augroup aucmd_win_test1 au! au BufEnter * call add(g:blist, [expand('<afile>'), \ win_gettype(bufwinnr(expand('<afile>')))]) augroup END doautoall BufEnter call assert_equal([ \ ['one.txt', 'autocmd'], \ ['two.txt', ''], \ ['four.txt', 'autocmd'], \ ['three.txt', ''], \ ], g:blist) augroup aucmd_win_test1 au! augroup END augroup! aucmd_win_test1 %bw! endfunc " Test for trying to close the temporary window used for executing an autocmd func Test_close_autocmd_window() %bw! edit one.txt tabnew two.txt augroup aucmd_win_test2 au! au BufEnter * if expand('<afile>') == 'one.txt' | 1close | endif augroup END call assert_fails('doautoall BufEnter', 'E813:') augroup aucmd_win_test2 au! augroup END augroup! aucmd_win_test2 %bwipe! endfunc " Test for trying to close the tab that has the temporary window for exeucing " an autocmd. func Test_close_autocmd_tab() edit one.txt tabnew two.txt augroup aucmd_win_test au! au BufEnter * if expand('<afile>') == 'one.txt' | tabfirst | tabonly | endif augroup END call assert_fails('doautoall BufEnter', 'E813:') tabonly augroup aucmd_win_test au! augroup END augroup! aucmd_win_test %bwipe! endfunc func Test_Visual_doautoall_redraw() call setline(1, ['a', 'b']) new wincmd p call feedkeys("G\<C-V>", 'txn') autocmd User Explode ++once redraw doautoall User Explode %bwipe! endfunc " This was using freed memory. func Test_BufNew_arglocal() arglocal au BufNew * arglocal call assert_fails('drop xx', 'E1156:') au! BufNew endfunc func Test_autocmd_closes_window() au BufNew,BufWinLeave * e %e file yyy au BufNew,BufWinLeave * ball n xxx %bwipe au! BufNew au! BufWinLeave endfunc func Test_autocmd_quit_psearch() sn aa bb augroup aucmd_win_test au! au BufEnter,BufLeave,BufNew,WinEnter,WinLeave,WinNew * if winnr('$') > 1 | q | endif augroup END ps / augroup aucmd_win_test au! augroup END new pclose endfunc " Fuzzer found some strange combination that caused a crash. func Test_autocmd_normal_mess() " For unknown reason this hangs on MS-Windows CheckNotMSWindows augroup aucmd_normal_test au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc augroup END call assert_fails('o4', 'E1159') silent! H call assert_fails('e xx', 'E1159') normal G augroup aucmd_normal_test au! augroup END endfunc func Test_autocmd_closing_cmdwin() " For unknown reason this hangs on MS-Windows CheckNotMSWindows au BufWinLeave * nested q call assert_fails("norm 7q?\n", 'E855:') au! BufWinLeave new only endfunc func Test_autocmd_vimgrep() augroup aucmd_vimgrep au QuickfixCmdPre,BufNew,BufReadCmd * sb au QuickfixCmdPre,BufNew,BufReadCmd * q9 augroup END call assert_fails('lv ?a? foo', 'E926:') augroup aucmd_vimgrep au! augroup END endfunc func Test_autocmd_with_block() augroup block_testing au BufReadPost *.xml { setlocal matchpairs+=<:> /<start } au CursorHold * { autocmd BufReadPre * ++once echo 'one' | echo 'two' g:gotSafeState = 77 } augroup END let expected = "\n--- Autocommands ---\nblock_testing BufRead\n *.xml {^@ setlocal matchpairs+=<:>^@ /<start^@ }" call assert_equal(expected, execute('au BufReadPost *.xml')) doautocmd CursorHold call assert_equal(77, g:gotSafeState) unlet g:gotSafeState augroup block_testing au! autocmd CursorHold * { if true # comment && true && true g:done = 'yes' endif } augroup END doautocmd CursorHold call assert_equal('yes', g:done) unlet g:done augroup block_testing au! augroup END endfunc " Test TextChangedI and TextChanged func Test_Changed_ChangedI() new call test_override("char_avail", 1) let [g:autocmd_i, g:autocmd_n] = ['',''] func! TextChangedAutocmdI(char) let g:autocmd_{tolower(a:char)} = a:char .. b:changedtick endfunc augroup Test_TextChanged au! au TextChanged <buffer> :call TextChangedAutocmdI('N') au TextChangedI <buffer> :call TextChangedAutocmdI('I') augroup END call feedkeys("ifoo\<esc>", 'tnix') " TODO: Test test does not seem to trigger TextChanged autocommand, this " requires running Vim in a terminal window. " call assert_equal('N3', g:autocmd_n) call assert_equal('I3', g:autocmd_i) call feedkeys("yyp", 'tnix') " TODO: Test test does not seem to trigger TextChanged autocommand. " call assert_equal('N4', g:autocmd_n) call assert_equal('I3', g:autocmd_i) " TextChangedI should only trigger if change was done in Insert mode let g:autocmd_i = '' call feedkeys("yypi\<esc>", 'tnix') call assert_equal('', g:autocmd_i) " TextChanged should only trigger if change was done in Normal mode let g:autocmd_n = '' call feedkeys("ibar\<esc>", 'tnix') call assert_equal('', g:autocmd_n) " If change is a mix of Normal and Insert modes, TextChangedI should trigger func s:validate_mixed_textchangedi(keys) call feedkeys("ifoo\<esc>", 'tnix') let g:autocmd_i = '' let g:autocmd_n = '' call feedkeys(a:keys, 'tnix') call assert_notequal('', g:autocmd_i) call assert_equal('', g:autocmd_n) endfunc call s:validate_mixed_textchangedi("o\<esc>") call s:validate_mixed_textchangedi("O\<esc>") call s:validate_mixed_textchangedi("ciw\<esc>") call s:validate_mixed_textchangedi("cc\<esc>") call s:validate_mixed_textchangedi("C\<esc>") call s:validate_mixed_textchangedi("s\<esc>") call s:validate_mixed_textchangedi("S\<esc>") " CleanUp call test_override("char_avail", 0) au! TextChanged <buffer> au! TextChangedI <buffer> augroup! Test_TextChanged delfu TextChangedAutocmdI unlet! g:autocmd_i g:autocmd_n bw! endfunc func Test_closing_autocmd_window() let lines =<< trim END edit Xa.txt tabnew Xb.txt autocmd BufEnter Xa.txt unhide 1 doautoall BufEnter END call v9.CheckScriptFailure(lines, 'E814:') au! BufEnter bwipe Xa.txt bwipe Xb.txt endfunc func Test_switch_window_in_autocmd_window() edit Xa.txt tabnew Xb.txt autocmd BufEnter Xa.txt wincmd w doautoall BufEnter au! BufEnter bwipe Xa.txt call assert_false(bufexists('Xa.txt')) bwipe Xb.txt call assert_false(bufexists('Xb.txt')) endfunc func Test_bufwipeout_changes_window() " This should not crash, but we don't have any expectations about what " happens, changing window in BufWipeout has unpredictable results. tabedit let g:window_id = win_getid() topleft new setlocal bufhidden=wipe autocmd BufWipeout <buffer> call win_gotoid(g:window_id) tabprevious +tabclose unlet g:window_id au! BufWipeout %bwipe! endfunc func Test_v_event_readonly() autocmd CompleteChanged * let v:event.width = 0 call assert_fails("normal! i\<C-X>\<C-V>", 'E46:') au! CompleteChanged autocmd DirChangedPre * let v:event.directory = '' call assert_fails('cd .', 'E46:') au! DirChangedPre autocmd ModeChanged * let v:event.new_mode = '' call assert_fails('normal! cc', 'E46:') au! ModeChanged autocmd TextYankPost * let v:event.operator = '' call assert_fails('normal! yy', 'E46:') au! TextYankPost endfunc " Test for ModeChanged pattern func Test_mode_changes() let g:index = 0 let g:mode_seq = ['n', 'i', 'n', 'v', 'V', 'i', 'ix', 'i', 'ic', 'i', 'n', 'no', 'noV', 'n', 'V', 'v', 's', 'n'] func! TestMode() call assert_equal(g:mode_seq[g:index], get(v:event, "old_mode")) call assert_equal(g:mode_seq[g:index + 1], get(v:event, "new_mode")) call assert_equal(mode(1), get(v:event, "new_mode")) let g:index += 1 endfunc au ModeChanged * :call TestMode() let g:n_to_any = 0 au ModeChanged n:* let g:n_to_any += 1 call feedkeys("i\<esc>vVca\<CR>\<C-X>\<C-L>\<esc>ggdV\<MouseMove>G", 'tnix') let g:V_to_v = 0 au ModeChanged V:v let g:V_to_v += 1 call feedkeys("Vv\<C-G>\<esc>", 'tnix') call assert_equal(len(filter(g:mode_seq[1:], {idx, val -> val == 'n'})), g:n_to_any) call assert_equal(1, g:V_to_v) call assert_equal(len(g:mode_seq) - 1, g:index) let g:n_to_i = 0 au ModeChanged n:i let g:n_to_i += 1 let g:n_to_niI = 0 au ModeChanged i:niI let g:n_to_niI += 1 let g:niI_to_i = 0 au ModeChanged niI:i let g:niI_to_i += 1 let g:nany_to_i = 0 au ModeChanged n*:i let g:nany_to_i += 1 let g:i_to_n = 0 au ModeChanged i:n let g:i_to_n += 1 let g:nori_to_any = 0 au ModeChanged [ni]:* let g:nori_to_any += 1 let g:i_to_any = 0 au ModeChanged i:* let g:i_to_any += 1 let g:index = 0 let g:mode_seq = ['n', 'i', 'niI', 'i', 'n'] call feedkeys("a\<C-O>l\<esc>", 'tnix') call assert_equal(len(g:mode_seq) - 1, g:index) call assert_equal(1, g:n_to_i) call assert_equal(1, g:n_to_niI) call assert_equal(1, g:niI_to_i) call assert_equal(2, g:nany_to_i) call assert_equal(1, g:i_to_n) call assert_equal(2, g:i_to_any) call assert_equal(3, g:nori_to_any) if has('terminal') let g:mode_seq += ['c', 'n', 't', 'nt', 'c', 'nt', 'n'] call feedkeys(":term\<CR>\<C-W>N:bd!\<CR>", 'tnix') call assert_equal(len(g:mode_seq) - 1, g:index) call assert_equal(1, g:n_to_i) call assert_equal(1, g:n_to_niI) call assert_equal(1, g:niI_to_i) call assert_equal(2, g:nany_to_i) call assert_equal(1, g:i_to_n) call assert_equal(2, g:i_to_any) call assert_equal(5, g:nori_to_any) endif let g:n_to_c = 0 au ModeChanged n:c let g:n_to_c += 1 let g:c_to_n = 0 au ModeChanged c:n let g:c_to_n += 1 let g:mode_seq += ['c', 'n', 'c', 'n'] call feedkeys("q:\<C-C>\<Esc>", 'tnix') call assert_equal(len(g:mode_seq) - 1, g:index) call assert_equal(2, g:n_to_c) call assert_equal(2, g:c_to_n) let g:n_to_v = 0 au ModeChanged n:v let g:n_to_v += 1 let g:v_to_n = 0 au ModeChanged v:n let g:v_to_n += 1 let g:mode_seq += ['v', 'n'] call feedkeys("v\<C-C>", 'tnix') call assert_equal(len(g:mode_seq) - 1, g:index) call assert_equal(1, g:n_to_v) call assert_equal(1, g:v_to_n) let g:mode_seq += ['c', 'cr', 'c', 'cr', 'n'] call feedkeys(":\<Insert>\<Insert>\<Insert>\<CR>", 'tnix') call assert_equal(len(g:mode_seq) - 1, g:index) au! ModeChanged delfunc TestMode unlet! g:mode_seq unlet! g:index unlet! g:n_to_any unlet! g:V_to_v unlet! g:n_to_i unlet! g:n_to_niI unlet! g:niI_to_i unlet! g:nany_to_i unlet! g:i_to_n unlet! g:nori_to_any unlet! g:i_to_any unlet! g:n_to_c unlet! g:c_to_n unlet! g:n_to_v unlet! g:v_to_n endfunc func Test_recursive_ModeChanged() au! ModeChanged * norm 0u sil! norm au! ModeChanged endfunc func Test_ModeChanged_starts_visual() " This was triggering ModeChanged before setting VIsual, causing a crash. au! ModeChanged * norm 0u sil! norm au! ModeChanged endfunc func Test_noname_autocmd() augroup test_noname_autocmd_group autocmd! autocmd BufEnter * call add(s:li, ["BufEnter", expand("<afile>")]) autocmd BufDelete * call add(s:li, ["BufDelete", expand("<afile>")]) autocmd BufLeave * call add(s:li, ["BufLeave", expand("<afile>")]) autocmd BufUnload * call add(s:li, ["BufUnload", expand("<afile>")]) autocmd BufWipeout * call add(s:li, ["BufWipeout", expand("<afile>")]) augroup END let s:li = [] edit foo call assert_equal([['BufUnload', ''], ['BufDelete', ''], ['BufWipeout', ''], ['BufEnter', 'foo']], s:li) au! test_noname_autocmd_group augroup! test_noname_autocmd_group endfunc " Test for the autocmd_get() function func Test_autocmd_get() augroup TestAutoCmdFns au! autocmd BufAdd *.vim echo "bufadd-vim" autocmd BufAdd *.py echo "bufadd-py" autocmd BufHidden *.vim echo "bufhidden" augroup END augroup TestAutoCmdFns2 autocmd BufAdd *.vim echo "bufadd-vim-2" autocmd BufRead *.a1b2c3 echo "bufadd-vim-2" augroup END let l = autocmd_get() call assert_true(l->len() > 0) " Test for getting all the autocmds in a group let expected = [ \ #{cmd: 'echo "bufadd-vim"', group: 'TestAutoCmdFns', \ pattern: '*.vim', nested: v:false, once: v:false, \ event: 'BufAdd'}, \ #{cmd: 'echo "bufadd-py"', group: 'TestAutoCmdFns', \ pattern: '*.py', nested: v:false, once: v:false, \ event: 'BufAdd'}, \ #{cmd: 'echo "bufhidden"', group: 'TestAutoCmdFns', \ pattern: '*.vim', nested: v:false, \ once: v:false, event: 'BufHidden'}] call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns'})) " Test for getting autocmds for all the patterns in a group call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns', \ event: '*'})) " Test for getting autocmds for an event in a group let expected = [ \ #{cmd: 'echo "bufadd-vim"', group: 'TestAutoCmdFns', \ pattern: '*.vim', nested: v:false, once: v:false, \ event: 'BufAdd'}, \ #{cmd: 'echo "bufadd-py"', group: 'TestAutoCmdFns', \ pattern: '*.py', nested: v:false, once: v:false, \ event: 'BufAdd'}] call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns', \ event: 'BufAdd'})) " Test for getting the autocmds for all the events in a group for particular " pattern call assert_equal([{'cmd': 'echo "bufadd-py"', 'group': 'TestAutoCmdFns', \ 'pattern': '*.py', 'nested': v:false, 'once': v:false, \ 'event': 'BufAdd'}], \ autocmd_get(#{group: 'TestAutoCmdFns', event: '*', pattern: '*.py'})) " Test for getting the autocmds for an events in a group for particular " pattern let l = autocmd_get(#{group: 'TestAutoCmdFns', event: 'BufAdd', \ pattern: '*.vim'}) call assert_equal([ \ #{cmd: 'echo "bufadd-vim"', group: 'TestAutoCmdFns', \ pattern: '*.vim', nested: v:false, once: v:false, \ event: 'BufAdd'}], l) " Test for getting the autocmds for a pattern in a group let l = autocmd_get(#{group: 'TestAutoCmdFns', pattern: '*.vim'}) call assert_equal([ \ #{cmd: 'echo "bufadd-vim"', group: 'TestAutoCmdFns', \ pattern: '*.vim', nested: v:false, once: v:false, \ event: 'BufAdd'}, \ #{cmd: 'echo "bufhidden"', group: 'TestAutoCmdFns', \ pattern: '*.vim', nested: v:false, \ once: v:false, event: 'BufHidden'}], l) " Test for getting the autocmds for a pattern in all the groups let l = autocmd_get(#{pattern: '*.a1b2c3'}) call assert_equal([{'cmd': 'echo "bufadd-vim-2"', 'group': 'TestAutoCmdFns2', \ 'pattern': '*.a1b2c3', 'nested': v:false, 'once': v:false, \ 'event': 'BufRead'}], l) " Test for getting autocmds for a pattern without any autocmds call assert_equal([], autocmd_get(#{group: 'TestAutoCmdFns', \ pattern: '*.abc'})) call assert_equal([], autocmd_get(#{group: 'TestAutoCmdFns', \ event: 'BufAdd', pattern: '*.abc'})) call assert_equal([], autocmd_get(#{group: 'TestAutoCmdFns', \ event: 'BufWipeout'})) call assert_fails("call autocmd_get(#{group: 'abc', event: 'BufAdd'})", \ 'E367:') let cmd = "echo autocmd_get(#{group: 'TestAutoCmdFns', event: 'abc'})" call assert_fails(cmd, 'E216:') call assert_fails("call autocmd_get(#{group: 'abc'})", 'E367:') call assert_fails("echo autocmd_get(#{event: 'abc'})", 'E216:') augroup TestAutoCmdFns au! augroup END call assert_equal([], autocmd_get(#{group: 'TestAutoCmdFns'})) " Test for nested and once autocmds augroup TestAutoCmdFns au! autocmd VimSuspend * ++nested echo "suspend" autocmd VimResume * ++once echo "resume" augroup END let expected = [ \ {'cmd': 'echo "suspend"', 'group': 'TestAutoCmdFns', 'pattern': '*', \ 'nested': v:true, 'once': v:false, 'event': 'VimSuspend'}, \ {'cmd': 'echo "resume"', 'group': 'TestAutoCmdFns', 'pattern': '*', \ 'nested': v:false, 'once': v:true, 'event': 'VimResume'}] call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns'})) " Test for buffer-local autocmd augroup TestAutoCmdFns au! autocmd TextYankPost <buffer> echo "textyankpost" augroup END let expected = [ \ {'cmd': 'echo "textyankpost"', 'group': 'TestAutoCmdFns', \ 'pattern': '<buffer=' .. bufnr() .. '>', 'nested': v:false, \ 'once': v:false, 'bufnr': bufnr(), 'event': 'TextYankPost'}] call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns'})) augroup TestAutoCmdFns au! augroup END augroup! TestAutoCmdFns augroup TestAutoCmdFns2 au! augroup END augroup! TestAutoCmdFns2 call assert_fails("echo autocmd_get(#{group: []})", 'E730:') call assert_fails("echo autocmd_get(#{event: {}})", 'E731:') call assert_fails("echo autocmd_get([])", 'E1206:') endfunc " Test for the autocmd_add() function func Test_autocmd_add() " Define a single autocmd in a group call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd', pattern: '*.sh', \ cmd: 'echo "bufadd"', once: v:true, nested: v:true}]) call assert_equal([#{cmd: 'echo "bufadd"', group: 'TestAcSet', \ pattern: '*.sh', nested: v:true, once: v:true, \ event: 'BufAdd'}], autocmd_get(#{group: 'TestAcSet'})) " Define two autocmds in the same group call autocmd_delete([#{group: 'TestAcSet'}]) call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd', pattern: '*.sh', \ cmd: 'echo "bufadd"'}, \ #{group: 'TestAcSet', event: 'BufEnter', pattern: '*.sh', \ cmd: 'echo "bufenter"'}]) call assert_equal([ \ #{cmd: 'echo "bufadd"', group: 'TestAcSet', pattern: '*.sh', \ nested: v:false, once: v:false, event: 'BufAdd'}, \ #{cmd: 'echo "bufenter"', group: 'TestAcSet', pattern: '*.sh', \ nested: v:false, once: v:false, event: 'BufEnter'}], \ autocmd_get(#{group: 'TestAcSet'})) " Define a buffer-local autocmd call autocmd_delete([#{group: 'TestAcSet'}]) call autocmd_add([#{group: 'TestAcSet', event: 'CursorHold', \ bufnr: bufnr(), cmd: 'echo "cursorhold"'}]) call assert_equal([ \ #{cmd: 'echo "cursorhold"', group: 'TestAcSet', \ pattern: '<buffer=' .. bufnr() .. '>', nested: v:false, \ once: v:false, bufnr: bufnr(), event: 'CursorHold'}], \ autocmd_get(#{group: 'TestAcSet'})) " Use an invalid buffer number call autocmd_delete([#{group: 'TestAcSet'}]) call autocmd_add([#{group: 'TestAcSet', event: 'BufEnter', \ bufnr: -1, cmd: 'echo "bufenter"'}]) let l = [#{group: 'TestAcSet', event: 'BufAdd', bufnr: 9999, \ cmd: 'echo "bufadd"'}] call assert_fails("echo autocmd_add(l)", 'E680:') let l = [#{group: 'TestAcSet', event: 'BufAdd', bufnr: 9999, \ pattern: '*.py', cmd: 'echo "bufadd"'}] call assert_fails("echo autocmd_add(l)", 'E680:') let l = [#{group: 'TestAcSet', event: 'BufAdd', bufnr: 9999, \ pattern: ['*.py', '*.c'], cmd: 'echo "bufadd"'}] call assert_fails("echo autocmd_add(l)", 'E680:') let l = [#{group: 'TestAcSet', event: 'BufRead', bufnr: [], \ cmd: 'echo "bufread"'}] call assert_fails("echo autocmd_add(l)", 'E745:') call assert_equal([], autocmd_get(#{group: 'TestAcSet'})) " Add two commands to the same group, event and pattern call autocmd_delete([#{group: 'TestAcSet'}]) call autocmd_add([#{group: 'TestAcSet', event: 'BufUnload', \ pattern: 'abc', cmd: 'echo "cmd1"'}]) call autocmd_add([#{group: 'TestAcSet', event: 'BufUnload', \ pattern: 'abc', cmd: 'echo "cmd2"'}]) call assert_equal([ \ #{cmd: 'echo "cmd1"', group: 'TestAcSet', pattern: 'abc', \ nested: v:false, once: v:false, event: 'BufUnload'}, \ #{cmd: 'echo "cmd2"', group: 'TestAcSet', pattern: 'abc', \ nested: v:false, once: v:false, event: 'BufUnload'}], \ autocmd_get(#{group: 'TestAcSet'})) " When adding a new autocmd, if the autocmd 'group' is not specified, then " the current autocmd group should be used. call autocmd_delete([#{group: 'TestAcSet'}]) augroup TestAcSet call autocmd_add([#{event: 'BufHidden', pattern: 'abc', cmd: 'echo "abc"'}]) augroup END call assert_equal([ \ #{cmd: 'echo "abc"', group: 'TestAcSet', pattern: 'abc', \ nested: v:false, once: v:false, event: 'BufHidden'}], \ autocmd_get(#{group: 'TestAcSet'})) " Test for replacing a cmd for an event in a group call autocmd_delete([#{group: 'TestAcSet'}]) call autocmd_add([#{replace: v:true, group: 'TestAcSet', event: 'BufEnter', \ pattern: '*.py', cmd: 'echo "bufenter"'}]) call autocmd_add([#{replace: v:true, group: 'TestAcSet', event: 'BufEnter', \ pattern: '*.py', cmd: 'echo "bufenter"'}]) call assert_equal([ \ #{cmd: 'echo "bufenter"', group: 'TestAcSet', pattern: '*.py', \ nested: v:false, once: v:false, event: 'BufEnter'}], \ autocmd_get(#{group: 'TestAcSet'})) " Test for adding a command for an unsupported autocmd event let l = [#{group: 'TestAcSet', event: 'abc', pattern: '*.sh', \ cmd: 'echo "bufadd"'}] call assert_fails('call autocmd_add(l)', 'E216:') " Test for using a list of events and patterns call autocmd_delete([#{group: 'TestAcSet'}]) let l = [#{group: 'TestAcSet', event: ['BufEnter', 'BufLeave'], \ pattern: ['*.py', '*.sh'], cmd: 'echo "bufcmds"'}] call autocmd_add(l) call assert_equal([ \ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.py', \ nested: v:false, once: v:false, event: 'BufEnter'}, \ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.sh', \ nested: v:false, once: v:false, event: 'BufEnter'}, \ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.py', \ nested: v:false, once: v:false, event: 'BufLeave'}, \ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.sh', \ nested: v:false, once: v:false, event: 'BufLeave'}], \ autocmd_get(#{group: 'TestAcSet'})) " Test for invalid values for 'event' item call autocmd_delete([#{group: 'TestAcSet'}]) let l = [#{group: 'TestAcSet', event: test_null_string(), \ pattern: "*.py", cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E928:') let l = [#{group: 'TestAcSet', event: test_null_list(), \ pattern: "*.py", cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E714:') let l = [#{group: 'TestAcSet', event: {}, \ pattern: "*.py", cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E777:') let l = [#{group: 'TestAcSet', event: [{}], \ pattern: "*.py", cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E928:') let l = [#{group: 'TestAcSet', event: [test_null_string()], \ pattern: "*.py", cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E928:') let l = [#{group: 'TestAcSet', event: 'BufEnter,BufLeave', \ pattern: '*.py', cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E216:') let l = [#{group: 'TestAcSet', event: [], \ pattern: "*.py", cmd: 'echo "bufcmds"'}] call autocmd_add(l) let l = [#{group: 'TestAcSet', event: [""], \ pattern: "*.py", cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E216:') let l = [#{group: 'TestAcSet', event: "", \ pattern: "*.py", cmd: 'echo "bufcmds"'}] call autocmd_add(l) call assert_equal([], autocmd_get(#{group: 'TestAcSet'})) " Test for invalid values for 'pattern' item let l = [#{group: 'TestAcSet', event: "BufEnter", \ pattern: test_null_string(), cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E928:') let l = [#{group: 'TestAcSet', event: "BufEnter", \ pattern: test_null_list(), cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E714:') let l = [#{group: 'TestAcSet', event: "BufEnter", \ pattern: {}, cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E777:') let l = [#{group: 'TestAcSet', event: "BufEnter", \ pattern: [{}], cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E928:') let l = [#{group: 'TestAcSet', event: "BufEnter", \ pattern: [test_null_string()], cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E928:') let l = [#{group: 'TestAcSet', event: "BufEnter", \ pattern: [], cmd: 'echo "bufcmds"'}] call autocmd_add(l) let l = [#{group: 'TestAcSet', event: "BufEnter", \ pattern: [""], cmd: 'echo "bufcmds"'}] call autocmd_add(l) let l = [#{group: 'TestAcSet', event: "BufEnter", \ pattern: "", cmd: 'echo "bufcmds"'}] call autocmd_add(l) call assert_equal([], autocmd_get(#{group: 'TestAcSet'})) let l = [#{group: 'TestAcSet', event: 'BufEnter,abc,BufLeave', \ pattern: '*.py', cmd: 'echo "bufcmds"'}] call assert_fails('call autocmd_add(l)', 'E216:') call assert_fails("call autocmd_add({})", 'E1211:') call assert_equal(v:false, autocmd_add(test_null_list())) call assert_true(autocmd_add([[]])) call assert_true(autocmd_add([test_null_dict()])) augroup TestAcSet au! augroup END call autocmd_add([#{group: 'TestAcSet'}]) call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd'}]) call autocmd_add([#{group: 'TestAcSet', pat: '*.sh'}]) call autocmd_add([#{group: 'TestAcSet', cmd: 'echo "a"'}]) call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd', pat: '*.sh'}]) call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd', cmd: 'echo "a"'}]) call autocmd_add([#{group: 'TestAcSet', pat: '*.sh', cmd: 'echo "a"'}]) call assert_equal([], autocmd_get(#{group: 'TestAcSet'})) augroup! TestAcSet endfunc " Test for deleting autocmd events and groups func Test_autocmd_delete() " Delete an event in an autocmd group augroup TestAcSet au! au BufAdd *.sh echo "bufadd" au BufEnter *.sh echo "bufenter" augroup END call autocmd_delete([#{group: 'TestAcSet', event: 'BufAdd'}]) call assert_equal([#{cmd: 'echo "bufenter"', group: 'TestAcSet', \ pattern: '*.sh', nested: v:false, once: v:false, \ event: 'BufEnter'}], autocmd_get(#{group: 'TestAcSet'})) " Delete all the events in an autocmd group augroup TestAcSet au BufAdd *.sh echo "bufadd" augroup END call autocmd_delete([#{group: 'TestAcSet', event: '*'}]) call assert_equal([], autocmd_get(#{group: 'TestAcSet'})) " Delete a non-existing autocmd group call assert_fails("call autocmd_delete([#{group: 'abc'}])", 'E367:') " Delete a non-existing autocmd event let l = [#{group: 'TestAcSet', event: 'abc'}] call assert_fails("call autocmd_delete(l)", 'E216:') " Delete a non-existing autocmd pattern let l = [#{group: 'TestAcSet', event: 'BufAdd', pat: 'abc'}] call assert_true(autocmd_delete(l)) " Delete an autocmd for a non-existing buffer let l = [#{event: '*', bufnr: 9999, cmd: 'echo "x"'}] call assert_fails('call autocmd_delete(l)', 'E680:') " Delete an autocmd group augroup TestAcSet au! au BufAdd *.sh echo "bufadd" au BufEnter *.sh echo "bufenter" augroup END call autocmd_delete([#{group: 'TestAcSet'}]) call assert_fails("call autocmd_get(#{group: 'TestAcSet'})", 'E367:') call assert_true(autocmd_delete([[]])) call assert_true(autocmd_delete([test_null_dict()])) endfunc func Test_autocmd_split_dummy() " Autocommand trying to split a window containing a dummy buffer. auto BufReadPre * exe "sbuf " .. expand("<abuf>") " Avoid the "W11" prompt au FileChangedShell * let v:fcs_choice = 'reload' func Xautocmd_changelist() cal writefile(['Xtestfile2:4:4'], 'Xerr') edit Xerr lex 'Xtestfile2:4:4' endfunc call Xautocmd_changelist() " Should get E86, but it doesn't always happen (timing?) silent! call Xautocmd_changelist() au! BufReadPre au! FileChangedShell delfunc Xautocmd_changelist bwipe! Xerr call delete('Xerr') endfunc " This was crashing because there was only one window to execute autocommands " in. func Test_autocmd_nested_setbufvar() CheckFeature python3 set hidden edit Xaaa edit Xbbb call setline(1, 'bar') enew au BufWriteCmd Xbbb ++nested call setbufvar('Xaaa', '&ft', 'foo') | bw! Xaaa au FileType foo call py3eval('vim.current.buffer.options["cindent"]') wall au! BufWriteCmd au! FileType foo set nohidden call delete('Xaaa') call delete('Xbbb') %bwipe! endfunc func SetupVimTest_shm() let g:bwe = [] let g:brp = [] set shortmess+=F messages clear let dirname='XVimTestSHM' call mkdir(dirname, 'R') call writefile(['test'], dirname .. '/1') call writefile(['test'], dirname .. '/2') call writefile(['test'], dirname .. '/3') augroup test autocmd! autocmd BufWinEnter * call add(g:bwe, $'BufWinEnter: {expand('<amatch>')}') autocmd BufReadPost * call add(g:brp, $'BufReadPost: {expand('<amatch>')}') augroup END call setqflist([ \ {'filename': dirname .. '/1', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0}, \ {'filename': dirname .. '/2', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0}, \ {'filename': dirname .. '/3', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0} \ ]) cdo! substitute/test/TEST " clean up noa enew! set shortmess&vim augroup test autocmd! augroup END augroup! test endfunc func Test_autocmd_shortmess() CheckNotMSWindows call SetupVimTest_shm() let output = execute(':mess')->split('\n') let info = copy(output)->filter({idx, val -> val =~# '\d of 3'} ) let bytes = copy(output)->filter({idx, val -> val =~# 'bytes'} ) " We test the following here: " BufReadPost should have been triggered 3 times, once per file " BufWinEnter should have been triggered 3 times, once per file " FileInfoMessage should have been shown 3 times, regardless of shm option " "(x of 3)" message from :cnext has been shown 3 times call assert_equal(3, g:brp->len()) call assert_equal(3, g:bwe->len()) call assert_equal(3, info->len()) call assert_equal(3, bytes->len()) delfunc SetupVimTest_shm endfunc func Test_autocmd_invalidates_undo_on_textchanged() CheckRunVimInTerminal let script =<< trim END set hidden " create quickfix list (at least 2 lines to move line) vimgrep /u/j % " enter quickfix window cwindow " set modifiable setlocal modifiable " set autocmd to clear quickfix list autocmd! TextChanged <buffer> call setqflist([]) " move line move+1 END call writefile(script, 'XTest_autocmd_invalidates_undo_on_textchanged', 'D') let buf = RunVimInTerminal('XTest_autocmd_invalidates_undo_on_textchanged', {'rows': 20}) call term_sendkeys(buf, ":so %\<cr>") call term_sendkeys(buf, "G") call WaitForAssert({-> assert_match('^XTest_autocmd_invalidates_undo_on_textchanged\s*$', term_getline(buf, 20))}, 1000) call StopVimInTerminal(buf) endfunc func Test_autocmd_creates_new_buffer_on_bufleave() e a.txt e b.txt setlocal bufhidden=wipe autocmd BufLeave <buffer> diffsplit c.txt bn call assert_equal(1, winnr('$')) call assert_equal('a.txt', bufname('%')) bw a.txt bw c.txt endfunc " Ensure `expected` was just recently written as a Vim session func s:assert_session_path(expected) call assert_equal(a:expected, v:this_session) endfunc " Check for `expected` after a session is written to-disk. func s:watch_for_session_path(expected) execute 'autocmd SessionWritePost * ++once execute "call s:assert_session_path(\"' \ . a:expected \ . '\")"' endfunc " Ensure v:this_session gets the full session path, if explicitly stated func Test_explicit_session_absolute_path() %bwipeout! let directory = getcwd() let v:this_session = "" let name = "some_file.vim" let expected = fnamemodify(name, ":p") call s:watch_for_session_path(expected) execute "mksession! " .. expected call delete(expected) endfunc " Ensure v:this_session gets the full session path, if explicitly stated func Test_explicit_session_relative_path() %bwipeout! let directory = getcwd() let v:this_session = "" let name = "some_file.vim" let expected = fnamemodify(name, ":p") call s:watch_for_session_path(expected) execute "mksession! " .. name call delete(expected) endfunc " Ensure v:this_session gets the full session path, if not specified func Test_implicit_session() %bwipeout! let directory = getcwd() let v:this_session = "" let expected = fnamemodify("Session.vim", ":p") call s:watch_for_session_path(expected) mksession! call delete(expected) endfunc " vim: shiftwidth=2 sts=2 expandtab