aboutsummaryrefslogtreecommitdiff
path: root/test/functional/autocmd
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2022-07-18 19:37:18 +0000
committerJosh Rahm <rahm@google.com>2022-07-18 19:37:18 +0000
commit308e1940dcd64aa6c344c403d4f9e0dda58d9c5c (patch)
tree35fe43e01755e0f312650667004487a44d6b7941 /test/functional/autocmd
parent96a00c7c588b2f38a2424aeeb4ea3581d370bf2d (diff)
parente8c94697bcbe23a5c7b07c292b90a6b70aadfa87 (diff)
downloadrneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.gz
rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.bz2
rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.zip
Merge remote-tracking branch 'upstream/master' into rahm
Diffstat (limited to 'test/functional/autocmd')
-rw-r--r--test/functional/autocmd/autocmd_oldtest_spec.lua86
-rw-r--r--test/functional/autocmd/autocmd_spec.lua223
-rw-r--r--test/functional/autocmd/cursormoved_spec.lua1
-rw-r--r--test/functional/autocmd/dirchanged_spec.lua128
-rw-r--r--test/functional/autocmd/focus_spec.lua2
-rw-r--r--test/functional/autocmd/show_spec.lua183
-rw-r--r--test/functional/autocmd/signal_spec.lua6
-rw-r--r--test/functional/autocmd/termxx_spec.lua26
-rw-r--r--test/functional/autocmd/winscrolled_spec.lua103
9 files changed, 697 insertions, 61 deletions
diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua
new file mode 100644
index 0000000000..ad3687d7b0
--- /dev/null
+++ b/test/functional/autocmd/autocmd_oldtest_spec.lua
@@ -0,0 +1,86 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local meths = helpers.meths
+local funcs = helpers.funcs
+
+local exec = function(str)
+ meths.exec(str, false)
+end
+
+describe('oldtests', function()
+ before_each(clear)
+
+ local exec_lines = function(str)
+ return funcs.split(funcs.execute(str), "\n")
+ end
+
+ local add_an_autocmd = function()
+ exec [[
+ augroup vimBarTest
+ au BufReadCmd * echo 'hello'
+ augroup END
+ ]]
+
+ eq(3, #exec_lines('au vimBarTest'))
+ eq(1, #meths.get_autocmds({ group = 'vimBarTest' }))
+ end
+
+ it('should recognize a bar before the {event}', function()
+ -- Good spacing
+ add_an_autocmd()
+ exec [[ augroup vimBarTest | au! | augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+ eq({}, meths.get_autocmds({ group = 'vimBarTest' }))
+
+ -- Sad spacing
+ add_an_autocmd()
+ exec [[ augroup vimBarTest| au!| augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+
+
+ -- test that a bar is recognized after the {event}
+ add_an_autocmd()
+ exec [[ augroup vimBarTest| au!BufReadCmd| augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+
+ add_an_autocmd()
+ exec [[ au! vimBarTest|echo 'hello' ]]
+ eq(1, #exec_lines('au vimBarTest'))
+ end)
+
+ it('should fire on unload buf', function()
+ funcs.writefile({'Test file Xxx1'}, 'Xxx1')
+ funcs.writefile({'Test file Xxx2'}, 'Xxx2')
+
+ local content = [[
+ 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')
+ set nohidden
+ edit Xxx1
+ split Xxx2
+ q
+ ]]
+
+ funcs.writefile(funcs.split(content, "\n"), 'Xtest')
+
+ funcs.delete('Xout')
+ funcs.system(meths.get_vvar('progpath') .. ' -u NORC -i NONE -N -S Xtest')
+ eq(1, funcs.filereadable('Xout'))
+
+ funcs.delete('Xxx1')
+ funcs.delete('Xxx2')
+ funcs.delete('Xtest')
+ funcs.delete('Xout')
+ end)
+end)
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 93d71a9e45..90254b7415 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -2,8 +2,10 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local assert_visible = helpers.assert_visible
+local assert_alive = helpers.assert_alive
local dedent = helpers.dedent
local eq = helpers.eq
+local neq = helpers.neq
local eval = helpers.eval
local feed = helpers.feed
local clear = helpers.clear
@@ -13,7 +15,9 @@ local funcs = helpers.funcs
local expect = helpers.expect
local command = helpers.command
local exc_exec = helpers.exc_exec
+local exec_lua = helpers.exec_lua
local curbufmeths = helpers.curbufmeths
+local retry = helpers.retry
local source = helpers.source
describe('autocmd', function()
@@ -56,6 +60,23 @@ describe('autocmd', function()
eq(expected, eval('g:evs'))
end)
+ it('first edit causes BufUnload on NoName', function()
+ local expected = {
+ {'BufUnload', ''},
+ {'BufDelete', ''},
+ {'BufWipeout', ''},
+ {'BufEnter', 'testfile1'},
+ }
+ command('let g:evs = []')
+ command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("<afile>")])')
+ command('autocmd BufDelete * :call add(g:evs, ["BufDelete", expand("<afile>")])')
+ command('autocmd BufLeave * :call add(g:evs, ["BufLeave", expand("<afile>")])')
+ command('autocmd BufUnload * :call add(g:evs, ["BufUnload", expand("<afile>")])')
+ command('autocmd BufWipeout * :call add(g:evs, ["BufWipeout", expand("<afile>")])')
+ command('edit testfile1')
+ eq(expected, eval('g:evs'))
+ end)
+
it('WinClosed is non-recursive', function()
command('let g:triggered = 0')
command('autocmd WinClosed * :let g:triggered+=1 | :bdelete 2')
@@ -333,6 +354,87 @@ describe('autocmd', function()
pcall_err(command, "call nvim_set_current_win(g:winid)"))
end)
+ it("`aucmd_win` cannot be changed into a normal window #13699", function()
+ local screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {reverse = true},
+ [3] = {bold = true, reverse = true},
+ }
+
+ -- Create specific layout and ensure it's left unchanged.
+ -- Use nvim_buf_call on a hidden buffer so aucmd_win is used.
+ exec_lua [[
+ vim.cmd "wincmd s | wincmd _"
+ _G.buf = vim.api.nvim_create_buf(true, true)
+ vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd J" end)
+ ]]
+ screen:expect [[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] }|
+ |
+ {2:[No Name] }|
+ |
+ ]]
+ -- This used to crash after making aucmd_win a normal window via the above.
+ exec_lua [[
+ vim.cmd "tabnew | tabclose # | wincmd s | wincmd _"
+ vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd K" end)
+ ]]
+ assert_alive()
+ screen:expect_unchanged()
+
+ -- Ensure splitting still works from inside the aucmd_win.
+ exec_lua [[vim.api.nvim_buf_call(_G.buf, function() vim.cmd "split" end)]]
+ screen:expect [[
+ ^ |
+ {1:~ }|
+ {3:[No Name] }|
+ |
+ {1:~ }|
+ {2:[Scratch] }|
+ |
+ {1:~ }|
+ {2:[No Name] }|
+ |
+ ]]
+
+ -- After all of our messing around, aucmd_win should still be floating.
+ -- Use :only to ensure _G.buf is hidden again (so the aucmd_win is used).
+ eq("editor", exec_lua [[
+ vim.cmd "only"
+ vim.api.nvim_buf_call(_G.buf, function()
+ _G.config = vim.api.nvim_win_get_config(0)
+ end)
+ return _G.config.relative
+ ]])
+ end)
+
+ describe('closing last non-floating window in tab from `aucmd_win`', function()
+ before_each(function()
+ command('edit Xa.txt')
+ command('tabnew Xb.txt')
+ command('autocmd BufAdd Xa.txt 1close')
+ end)
+
+ it('gives E814 when there are no other floating windows', function()
+ eq('Vim(close):E814: Cannot close window, only autocmd window would remain',
+ pcall_err(command, 'doautoall BufAdd'))
+ end)
+
+ it('gives E814 when there are other floating windows', function()
+ meths.open_win(0, true, {width = 10, height = 10, relative = 'editor', row = 10, col = 10})
+ eq('Vim(close):E814: Cannot close window, only autocmd window would remain',
+ pcall_err(command, 'doautoall BufAdd'))
+ end)
+ end)
+
it(':doautocmd does not warn "No matching autocommands" #10689', function()
local screen = Screen.new(32, 3)
screen:attach()
@@ -354,4 +456,125 @@ describe('autocmd', function()
:doautocmd SessionLoadPost |
]]}
end)
+
+ describe('v:event is readonly #18063', function()
+ it('during ChanOpen event', function()
+ command('autocmd ChanOpen * let v:event.info.id = 0')
+ funcs.jobstart({'cat'})
+ retry(nil, nil, function()
+ eq('E46: Cannot change read-only variable "v:event.info"', meths.get_vvar('errmsg'))
+ end)
+ end)
+
+ it('during ChanOpen event', function()
+ command('autocmd ChanInfo * let v:event.info.id = 0')
+ meths.set_client_info('foo', {}, 'remote', {}, {})
+ retry(nil, nil, function()
+ eq('E46: Cannot change read-only variable "v:event.info"', meths.get_vvar('errmsg'))
+ end)
+ end)
+
+ it('during RecordingLeave event', function()
+ command([[autocmd RecordingLeave * let v:event.regname = '']])
+ eq('Vim(let):E46: Cannot change read-only variable "v:event.regname"',
+ pcall_err(command, 'normal! qqq'))
+ end)
+
+ it('during TermClose event', function()
+ command('autocmd TermClose * let v:event.status = 0')
+ command('terminal')
+ eq('Vim(let):E46: Cannot change read-only variable "v:event.status"',
+ pcall_err(command, 'bdelete!'))
+ end)
+ end)
+
+ describe('old_tests', function()
+ it('vimscript: WinNew ++once', function()
+ source [[
+ " Without ++once WinNew triggers twice
+ let g:did_split = 0
+ augroup Testing
+ au!
+ 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:')
+ ]]
+
+ meths.set_var('did_split', 0)
+
+ source [[
+ augroup Testing
+ au!
+ au WinNew * let g:did_split += 1
+ augroup END
+
+ split
+ split
+ ]]
+
+ eq(2, meths.get_var('did_split'))
+ eq(1, funcs.exists('#WinNew'))
+
+ -- Now with once
+ meths.set_var('did_split', 0)
+
+ source [[
+ augroup Testing
+ au!
+ au WinNew * ++once let g:did_split += 1
+ augroup END
+
+ split
+ split
+ ]]
+
+ eq(1, meths.get_var('did_split'))
+ eq(0, funcs.exists('#WinNew'))
+
+ -- call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
+ local ok, msg = pcall(source, [[
+ au WinNew * ++once ++once echo bad
+ ]])
+
+ eq(false, ok)
+ eq(true, not not string.find(msg, 'E983:'))
+ end)
+
+ it('should have autocmds in filetypedetect group', function()
+ source [[filetype on]]
+ neq({}, meths.get_autocmds { group = "filetypedetect" })
+ end)
+
+ it('should allow comma-separated patterns', function()
+ source [[
+ augroup TestingPatterns
+ au!
+ autocmd BufReadCmd *.shada,*.shada.tmp.[a-z] echo 'hello'
+ autocmd BufReadCmd *.shada,*.shada.tmp.[a-z] echo 'hello'
+ augroup END
+ ]]
+
+ eq(4, #meths.get_autocmds { event = "BufReadCmd", group = "TestingPatterns" })
+ end)
+ end)
end)
diff --git a/test/functional/autocmd/cursormoved_spec.lua b/test/functional/autocmd/cursormoved_spec.lua
index 9641d4b096..85d8628d7e 100644
--- a/test/functional/autocmd/cursormoved_spec.lua
+++ b/test/functional/autocmd/cursormoved_spec.lua
@@ -35,6 +35,7 @@ describe('CursorMoved', function()
it("is not triggered by cursor movement prior to first CursorMoved instantiation", function()
source([[
let g:cursormoved = 0
+ autocmd! CursorMoved
autocmd CursorMoved * let g:cursormoved += 1
]])
eq(0, eval('g:cursormoved'))
diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua
index f4a1642ebf..45dc06b39b 100644
--- a/test/functional/autocmd/dirchanged_spec.lua
+++ b/test/functional/autocmd/dirchanged_spec.lua
@@ -8,7 +8,7 @@ local eval = h.eval
local request = h.request
local iswin = h.iswin
-describe('autocmd DirChanged', function()
+describe('autocmd DirChanged and DirChangedPre', function()
local curdir = string.gsub(lfs.currentdir(), '\\', '/')
local dirs = {
curdir .. '/Xtest-functional-autocmd-dirchanged.dir1',
@@ -26,31 +26,43 @@ describe('autocmd DirChanged', function()
before_each(function()
clear()
+ command('autocmd DirChangedPre * let [g:evpre, g:amatchpre, g:cdprecount] '
+ ..'= [copy(v:event), expand("<amatch>"), 1 + get(g:, "cdprecount", 0)]')
command('autocmd DirChanged * let [g:getcwd, g:ev, g:amatch, g:cdcount] '
- ..' = [getcwd(), copy(v:event), expand("<amatch>"), 1 + get(g:, "cdcount", 0)]')
+ ..'= [getcwd(), copy(v:event), expand("<amatch>"), 1 + get(g:, "cdcount", 0)]')
-- Normalize path separators.
+ command([[autocmd DirChangedPre * let g:evpre['directory'] = substitute(g:evpre['directory'], '\\', '/', 'g')]])
command([[autocmd DirChanged * let g:ev['cwd'] = substitute(g:ev['cwd'], '\\', '/', 'g')]])
- command([[autocmd DirChanged * let g:getcwd = substitute(g:getcwd, '\\', '/', 'g')]])
+ command([[autocmd DirChanged * let g:getcwd = substitute(g:getcwd, '\\', '/', 'g')]])
end)
- it('sets v:event and <amatch>', function()
+ it('set v:event and <amatch>', function()
command('lcd '..dirs[1])
+ eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch'))
+ eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
command('tcd '..dirs[2])
+ eq({directory=dirs[2], scope='tabpage', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[2], scope='tabpage', changed_window=false}, eval('g:ev'))
+ eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch'))
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
command('cd '..dirs[3])
+ eq({directory=dirs[3], scope='global', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[3], scope='global', changed_window=false}, eval('g:ev'))
+ eq('global', eval('g:amatchpre'))
eq('global', eval('g:amatch'))
+ eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
end)
- it('sets getcwd() during event #6260', function()
+ it('DirChanged set getcwd() during event #6260', function()
command('lcd '..dirs[1])
eq(dirs[1], eval('g:getcwd'))
@@ -61,7 +73,7 @@ describe('autocmd DirChanged', function()
eq(dirs[3], eval('g:getcwd'))
end)
- it('disallows recursion', function()
+ it('disallow recursion', function()
command('set shellslash')
-- Set up a _nested_ handler.
command('autocmd DirChanged * nested lcd '..dirs[3])
@@ -72,23 +84,36 @@ describe('autocmd DirChanged', function()
eq(dirs[3], eval('getcwd()'))
end)
- it('does not trigger if :cd fails', function()
+ it('only DirChangedPre is triggered if :cd fails', function()
command('let g:ev = {}')
+ command('let g:cdcount = 0')
local status1, err1 = pcall(function()
- command('lcd '..dirs[1] .. '/doesnotexist')
+ command('lcd '..dirs[1]..'/doesnotexist')
end)
+ eq({directory=dirs[1]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
+ eq(1, eval('g:cdprecount'))
+ eq(0, eval('g:cdcount'))
local status2, err2 = pcall(function()
- command('lcd '..dirs[2] .. '/doesnotexist')
+ command('lcd '..dirs[2]..'/doesnotexist')
end)
+ eq({directory=dirs[2]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
+ eq(2, eval('g:cdprecount'))
+ eq(0, eval('g:cdcount'))
local status3, err3 = pcall(function()
- command('lcd '..dirs[3] .. '/doesnotexist')
+ command('lcd '..dirs[3]..'/doesnotexist')
end)
+ eq({directory=dirs[3]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
+ eq(3, eval('g:cdprecount'))
+ eq(0, eval('g:cdcount'))
eq(false, status1)
eq(false, status2)
@@ -99,85 +124,121 @@ describe('autocmd DirChanged', function()
eq('E344:', string.match(err3, "E%d*:"))
end)
- it("is triggered by 'autochdir'", function()
+ it("are triggered by 'autochdir'", function()
command('set autochdir')
command('split '..dirs[1]..'/foo')
+ eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev'))
+ eq('auto', eval('g:amatchpre'))
eq('auto', eval('g:amatch'))
+ eq(1, eval('g:cdprecount'))
+ eq(1, eval('g:cdcount'))
command('split '..dirs[2]..'/bar')
+ eq({directory=dirs[2], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=false}, eval('g:ev'))
eq('auto', eval('g:amatch'))
-
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
end)
- it('does not trigger if directory has not changed', function()
+ it('do not trigger if directory has not changed', function()
command('lcd '..dirs[1])
+ eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch'))
+ eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
+ command('let g:evpre = {}')
command('let g:ev = {}')
command('lcd '..dirs[1])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
if iswin() then
command('lcd '..win_dirs[1])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
end
command('tcd '..dirs[2])
+ eq({directory=dirs[2], scope='tabpage', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[2], scope='tabpage', changed_window=false}, eval('g:ev'))
+ eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch'))
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
+ command('let g:evpre = {}')
command('let g:ev = {}')
command('tcd '..dirs[2])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
if iswin() then
command('tcd '..win_dirs[2])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
end
command('cd '..dirs[3])
+ eq({directory=dirs[3], scope='global', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[3], scope='global', changed_window=false}, eval('g:ev'))
eq('global', eval('g:amatch'))
+ eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
+ command('let g:evpre = {}')
command('let g:ev = {}')
command('cd '..dirs[3])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
if iswin() then
command('cd '..win_dirs[3])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
end
command('set autochdir')
command('split '..dirs[1]..'/foo')
+ eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev'))
+ eq('auto', eval('g:amatchpre'))
eq('auto', eval('g:amatch'))
+ eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
+ command('let g:evpre = {}')
command('let g:ev = {}')
command('split '..dirs[1]..'/bar')
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
if iswin() then
command('split '..win_dirs[1]..'/baz')
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
end
end)
- it("is triggered by switching to win/tab with different CWD #6054", function()
+ it("are triggered by switching to win/tab with different CWD #6054", function()
command('lcd '..dirs[3]) -- window 3
command('split '..dirs[2]..'/foo') -- window 2
command('lcd '..dirs[2])
@@ -185,72 +246,105 @@ describe('autocmd DirChanged', function()
command('lcd '..dirs[1])
command('2wincmd w') -- window 2
+ eq({directory=dirs[2], scope='window', changed_window=true}, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=true}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch'))
+ eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
command('tabnew') -- tab 2 (tab-local CWD)
+ eq(4, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(4, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tcd '..dirs[3])
command('tabnext') -- tab 1 (no tab-local CWD)
+ eq({directory=dirs[2], scope='window', changed_window=true}, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=true}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch'))
command('tabnext') -- tab 2
+ eq({directory=dirs[3], scope='tabpage', changed_window=true}, eval('g:evpre'))
eq({cwd=dirs[3], scope='tabpage', changed_window=true}, eval('g:ev'))
+ eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch'))
+ eq(7, eval('g:cdprecount'))
eq(7, eval('g:cdcount'))
command('tabnext') -- tab 1
command('3wincmd w') -- window 3
+ eq(9, eval('g:cdprecount'))
eq(9, eval('g:cdcount'))
command('tabnext') -- tab 2 (has the *same* CWD)
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
if iswin() then
command('tabnew') -- tab 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tcd '..win_dirs[3])
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 1
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 2
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 1
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('lcd '..win_dirs[3]) -- window 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 2
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 1
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
end
end)
- it('is triggered by nvim_set_current_dir()', function()
+ it('are triggered by nvim_set_current_dir()', function()
request('nvim_set_current_dir', dirs[1])
+ eq({directory=dirs[1], scope='global', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='global', changed_window=false}, eval('g:ev'))
+ eq(1, eval('g:cdprecount'))
+ eq(1, eval('g:cdcount'))
request('nvim_set_current_dir', dirs[2])
+ eq({directory=dirs[2], scope='global', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[2], scope='global', changed_window=false}, eval('g:ev'))
+ eq(2, eval('g:cdprecount'))
+ eq(2, eval('g:cdcount'))
local status, err = pcall(function()
request('nvim_set_current_dir', '/doesnotexist')
end)
eq(false, status)
eq('Failed to change directory', string.match(err, ': (.*)'))
- eq({cwd=dirs[2], scope='global', changed_window=false}, eval('g:ev'))
+ eq({directory='/doesnotexist', scope='global', changed_window=false}, eval('g:evpre'))
+ eq(3, eval('g:cdprecount'))
+ eq(2, eval('g:cdcount'))
end)
- it('works when local to buffer', function()
+ it('work when local to buffer', function()
+ command('let g:triggeredpre = 0')
command('let g:triggered = 0')
+ command('autocmd DirChangedPre <buffer> let g:triggeredpre = 1')
command('autocmd DirChanged <buffer> let g:triggered = 1')
command('cd '..dirs[1])
+ eq(1, eval('g:triggeredpre'))
eq(1, eval('g:triggered'))
end)
end)
diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua
index 3f9a0ad09b..e3c9e1f9ee 100644
--- a/test/functional/autocmd/focus_spec.lua
+++ b/test/functional/autocmd/focus_spec.lua
@@ -56,7 +56,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
line 3 |
line 4 |
{5:xtest-foo }|
- "xtest-foo" 4L, 28C |
+ "xtest-foo" 4L, 28B |
{3:-- TERMINAL --} |
]]}
end)
diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua
new file mode 100644
index 0000000000..505bed834b
--- /dev/null
+++ b/test/functional/autocmd/show_spec.lua
@@ -0,0 +1,183 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local clear = helpers.clear
+local command = helpers.command
+local dedent = helpers.dedent
+local eq = helpers.eq
+local funcs = helpers.funcs
+local eval = helpers.eval
+local exec = helpers.exec
+local feed = helpers.feed
+
+describe(":autocmd", function()
+ before_each(function()
+ clear({'-u', 'NONE'})
+ end)
+
+ it("should not segfault when you just do autocmd", function()
+ command ":autocmd"
+ end)
+
+ it("should filter based on ++once", function()
+ command "autocmd! BufEnter"
+ command "autocmd BufEnter * :echo 'Hello'"
+ command [[augroup TestingOne]]
+ command [[ autocmd BufEnter * :echo "Line 1"]]
+ command [[ autocmd BufEnter * :echo "Line 2"]]
+ command [[augroup END]]
+
+ eq(dedent([[
+
+ --- Autocommands ---
+ BufEnter
+ * :echo 'Hello'
+ TestingOne BufEnter
+ * :echo "Line 1"
+ :echo "Line 2"]]),
+ funcs.execute('autocmd BufEnter'))
+ end)
+
+ it('should not show group information if interrupted', function()
+ local screen = Screen.new(50, 6)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ [2] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [3] = {bold = true, foreground = Screen.colors.Magenta}, -- Title
+ })
+ screen:attach()
+ exec([[
+ set more
+ autocmd! BufEnter
+ augroup test_1
+ autocmd BufEnter A echo 'A'
+ autocmd BufEnter B echo 'B'
+ autocmd BufEnter C echo 'C'
+ autocmd BufEnter D echo 'D'
+ autocmd BufEnter E echo 'E'
+ autocmd BufEnter F echo 'F'
+ augroup END
+ autocmd! BufLeave
+ augroup test_1
+ autocmd BufLeave A echo 'A'
+ autocmd BufLeave B echo 'B'
+ autocmd BufLeave C echo 'C'
+ autocmd BufLeave D echo 'D'
+ autocmd BufLeave E echo 'E'
+ autocmd BufLeave F echo 'F'
+ augroup END
+ ]])
+ feed(':autocmd<CR>')
+ screen:expect([[
+ :autocmd |
+ {3:--- Autocommands ---} |
+ {3:test_1} {3:BufEnter} |
+ A echo 'A' |
+ B echo 'B' |
+ {2:-- More --}^ |
+ ]])
+ feed('q')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('should not show group information for deleted pattern', function()
+ exec([[
+ autocmd! BufEnter
+ augroup test_1
+ autocmd BufEnter A echo 'A'
+ autocmd BufEnter B echo 'B'
+ autocmd BufEnter C echo 'C'
+ augroup END
+ augroup test_2
+ autocmd BufEnter foo echo 'foo'
+ augroup END
+ augroup test_3
+ autocmd BufEnter D echo 'D'
+ autocmd BufEnter E echo 'E'
+ autocmd BufEnter F echo 'F'
+ augroup END
+
+ func Func()
+ autocmd! test_2 BufEnter
+ let g:output = execute('autocmd BufEnter')
+ endfunc
+
+ autocmd User foo call Func()
+ doautocmd User foo
+ ]])
+ eq(dedent([[
+
+ --- Autocommands ---
+ test_1 BufEnter
+ A echo 'A'
+ B echo 'B'
+ C echo 'C'
+ test_3 BufEnter
+ D echo 'D'
+ E echo 'E'
+ F echo 'F']]), eval('g:output'))
+ end)
+
+ it('can filter by pattern #17973', function()
+ exec([[
+ autocmd! BufEnter
+ autocmd! User
+ augroup test_1
+ autocmd BufEnter A echo "A1"
+ autocmd BufEnter B echo "B1"
+ autocmd User A echo "A1"
+ autocmd User B echo "B1"
+ augroup END
+ augroup test_2
+ autocmd BufEnter A echo "A2"
+ autocmd BufEnter B echo "B2"
+ autocmd User A echo "A2"
+ autocmd User B echo "B2"
+ augroup END
+ augroup test_3
+ autocmd BufEnter A echo "A3"
+ autocmd BufEnter B echo "B3"
+ autocmd User A echo "A3"
+ autocmd User B echo "B3"
+ augroup END
+ ]])
+ eq(dedent([[
+
+ --- Autocommands ---
+ test_1 User
+ A echo "A1"
+ test_2 User
+ A echo "A2"
+ test_3 User
+ A echo "A3"]]), funcs.execute('autocmd User A'))
+ eq(dedent([[
+
+ --- Autocommands ---
+ test_1 BufEnter
+ B echo "B1"
+ test_2 BufEnter
+ B echo "B2"
+ test_3 BufEnter
+ B echo "B3"
+ test_1 User
+ B echo "B1"
+ test_2 User
+ B echo "B2"
+ test_3 User
+ B echo "B3"]]), funcs.execute('autocmd * B'))
+ eq(dedent([[
+
+ --- Autocommands ---
+ test_3 BufEnter
+ B echo "B3"
+ test_3 User
+ B echo "B3"]]), funcs.execute('autocmd test_3 * B'))
+ end)
+end)
diff --git a/test/functional/autocmd/signal_spec.lua b/test/functional/autocmd/signal_spec.lua
index 719adeaf1b..d4f65cc61d 100644
--- a/test/functional/autocmd/signal_spec.lua
+++ b/test/functional/autocmd/signal_spec.lua
@@ -30,6 +30,12 @@ describe('autocmd Signal', function()
eq({'notification', 'foo', {}}, next_msg())
end)
+ it('matches SIGWINCH', function()
+ command('autocmd Signal SIGWINCH call rpcnotify(1, "foo")')
+ posix_kill('WINCH', funcs.getpid())
+ eq({'notification', 'foo', {}}, next_msg())
+ end)
+
it('does not match unknown patterns', function()
command('autocmd Signal SIGUSR2 call rpcnotify(1, "foo")')
posix_kill('USR1', funcs.getpid())
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index 1e8f981437..859c2ebf44 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -1,21 +1,41 @@
local luv = require('luv')
local helpers = require('test.functional.helpers')(after_each)
-local clear, command, nvim, nvim_dir =
- helpers.clear, helpers.command, helpers.nvim, helpers.nvim_dir
+local clear, command, nvim, testprg =
+ helpers.clear, helpers.command, helpers.nvim, helpers.testprg
local eval, eq, neq, retry =
helpers.eval, helpers.eq, helpers.neq, helpers.retry
local ok = helpers.ok
local feed = helpers.feed
+local pcall_err = helpers.pcall_err
+local assert_alive = helpers.assert_alive
local iswin = helpers.iswin
describe('autocmd TermClose', function()
before_each(function()
clear()
- nvim('set_option', 'shell', nvim_dir .. '/shell-test')
+ nvim('set_option', 'shell', testprg('shell-test'))
command('set shellcmdflag=EXE shellredir= shellpipe= shellquote= shellxquote=')
end)
+
+ local function test_termclose_delete_own_buf()
+ command('autocmd TermClose * bdelete!')
+ command('terminal')
+ eq('Vim(bdelete):E937: Attempt to delete a buffer that is in use', pcall_err(command, 'bdelete!'))
+ assert_alive()
+ end
+
+ -- TODO: fixed after merging patches for `can_unload_buffer`?
+ pending('TermClose deleting its own buffer, altbuf = buffer 1 #10386', function()
+ test_termclose_delete_own_buf()
+ end)
+
+ it('TermClose deleting its own buffer, altbuf NOT buffer 1 #10386', function()
+ command('edit foo1')
+ test_termclose_delete_own_buf()
+ end)
+
it('triggers when fast-exiting terminal job stops', function()
command('autocmd TermClose * let g:test_termclose = 23')
command('terminal')
diff --git a/test/functional/autocmd/winscrolled_spec.lua b/test/functional/autocmd/winscrolled_spec.lua
index 1ef5a37479..5c1b758961 100644
--- a/test/functional/autocmd/winscrolled_spec.lua
+++ b/test/functional/autocmd/winscrolled_spec.lua
@@ -3,60 +3,83 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
-local source = helpers.source
+local command = helpers.command
+local feed = helpers.feed
+local meths = helpers.meths
+local assert_alive = helpers.assert_alive
+
+before_each(clear)
describe('WinScrolled', function()
- before_each(clear)
+ local win_id
+
+ before_each(function()
+ win_id = meths.get_current_win().id
+ command(string.format('autocmd WinScrolled %d let g:matched = v:true', win_id))
+ command('let g:scrolled = 0')
+ command('autocmd WinScrolled * let g:scrolled += 1')
+ command([[autocmd WinScrolled * let g:amatch = str2nr(expand('<amatch>'))]])
+ command([[autocmd WinScrolled * let g:afile = str2nr(expand('<afile>'))]])
+ end)
+
+ after_each(function()
+ eq(true, eval('g:matched'))
+ eq(win_id, eval('g:amatch'))
+ eq(win_id, eval('g:afile'))
+ end)
it('is triggered by scrolling vertically', function()
- source([[
- set nowrap
- let width = winwidth(0)
- let line = '123' . repeat('*', width * 2)
- let lines = [line, line]
- call nvim_buf_set_lines(0, 0, -1, v:true, lines)
-
- let g:scrolled = 0
- autocmd WinScrolled * let g:scrolled += 1
- execute "normal! \<C-e>"
- ]])
+ local lines = {'123', '123'}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ eq(0, eval('g:scrolled'))
+ feed('<C-E>')
eq(1, eval('g:scrolled'))
end)
it('is triggered by scrolling horizontally', function()
- source([[
- set nowrap
- let width = winwidth(0)
- let line = '123' . repeat('*', width * 2)
- let lines = [line, line]
- call nvim_buf_set_lines(0, 0, -1, v:true, lines)
-
- let g:scrolled = 0
- autocmd WinScrolled * let g:scrolled += 1
- execute "normal! zl"
- ]])
+ command('set nowrap')
+ local width = meths.win_get_width(0)
+ local line = '123' .. ('*'):rep(width * 2)
+ local lines = {line, line}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ eq(0, eval('g:scrolled'))
+ feed('zl')
eq(1, eval('g:scrolled'))
end)
- it('is triggered when the window scrolls in insert mode', function()
- source([[
- let height = winheight(0)
- let lines = map(range(height * 2), {_, i -> string(i)})
- call nvim_buf_set_lines(0, 0, -1, v:true, lines)
-
- let g:scrolled = 0
- autocmd WinScrolled * let g:scrolled += 1
- call feedkeys("LA\<CR><Esc>", "n")
- ]])
+ it('is triggered by horizontal scrolling from cursor move', function()
+ command('set nowrap')
+ local lines = {'', '', 'Foo'}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ meths.win_set_cursor(0, {3, 0})
+ eq(0, eval('g:scrolled'))
+ feed('zl')
+ eq(1, eval('g:scrolled'))
+ feed('zl')
eq(2, eval('g:scrolled'))
+ feed('h')
+ eq(3, eval('g:scrolled'))
end)
- it('is triggered when the window is resized', function()
- source([[
- let g:scrolled = 0
- autocmd WinScrolled * let g:scrolled += 1
- wincmd v
- ]])
+ it('is triggered when the window scrolls in Insert mode', function()
+ local height = meths.win_get_height(0)
+ local lines = {}
+ for i = 1, height * 2 do
+ lines[i] = tostring(i)
+ end
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ feed('L')
+ eq(0, eval('g:scrolled'))
+ feed('A<CR><Esc>')
eq(1, eval('g:scrolled'))
end)
end)
+
+it('closing window in WinScrolled does not cause use-after-free #13265', function()
+ local lines = {'aaa', 'bbb'}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ command('vsplit')
+ command('autocmd WinScrolled * close')
+ feed('<C-E>')
+ assert_alive()
+end)