dirchanged_spec.lua (13622B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 4 local clear = n.clear 5 local command = n.command 6 local eq = t.eq 7 local eval = n.eval 8 local request = n.request 9 local is_os = t.is_os 10 11 describe('autocmd DirChanged and DirChangedPre', function() 12 local curdir = t.fix_slashes(vim.uv.cwd()) 13 local dirs = { 14 curdir .. '/Xtest-functional-autocmd-dirchanged.dir1', 15 curdir .. '/Xtest-functional-autocmd-dirchanged.dir2', 16 curdir .. '/Xtest-functional-autocmd-dirchanged.dir3', 17 } 18 local win_dirs = { 19 curdir .. '\\XTEST-FUNCTIONAL-AUTOCMD-DIRCHANGED.DIR1', 20 curdir .. '\\XTEST-FUNCTIONAL-AUTOCMD-DIRCHANGED.DIR2', 21 curdir .. '\\XTEST-FUNCTIONAL-AUTOCMD-DIRCHANGED.DIR3', 22 } 23 24 setup(function() 25 for _, dir in pairs(dirs) do 26 t.mkdir(dir) 27 end 28 end) 29 teardown(function() 30 for _, dir in pairs(dirs) do 31 n.rmdir(dir) 32 end 33 end) 34 35 before_each(function() 36 clear() 37 command( 38 'autocmd DirChangedPre * let [g:evpre, g:amatchpre, g:cdprecount] ' 39 .. '= [copy(v:event), expand("<amatch>"), 1 + get(g:, "cdprecount", 0)]' 40 ) 41 command( 42 'autocmd DirChanged * let [g:getcwd, g:ev, g:amatch, g:cdcount] ' 43 .. '= [getcwd(), copy(v:event), expand("<amatch>"), 1 + get(g:, "cdcount", 0)]' 44 ) 45 -- Normalize path separators. 46 command( 47 [[autocmd DirChangedPre * let g:evpre['directory'] = substitute(g:evpre['directory'], '\\', '/', 'g')]] 48 ) 49 command([[autocmd DirChanged * let g:ev['cwd'] = substitute(g:ev['cwd'], '\\', '/', 'g')]]) 50 command([[autocmd DirChanged * let g:getcwd = substitute(g:getcwd, '\\', '/', 'g')]]) 51 end) 52 53 it('set v:event and <amatch>', function() 54 command('lcd ' .. dirs[1]) 55 eq({ directory = dirs[1], scope = 'window', changed_window = false }, eval('g:evpre')) 56 eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev')) 57 eq('window', eval('g:amatchpre')) 58 eq('window', eval('g:amatch')) 59 eq(1, eval('g:cdprecount')) 60 eq(1, eval('g:cdcount')) 61 62 command('tcd ' .. dirs[2]) 63 eq({ directory = dirs[2], scope = 'tabpage', changed_window = false }, eval('g:evpre')) 64 eq({ cwd = dirs[2], scope = 'tabpage', changed_window = false }, eval('g:ev')) 65 eq('tabpage', eval('g:amatchpre')) 66 eq('tabpage', eval('g:amatch')) 67 eq(2, eval('g:cdprecount')) 68 eq(2, eval('g:cdcount')) 69 70 command('cd ' .. dirs[3]) 71 eq({ directory = dirs[3], scope = 'global', changed_window = false }, eval('g:evpre')) 72 eq({ cwd = dirs[3], scope = 'global', changed_window = false }, eval('g:ev')) 73 eq('global', eval('g:amatchpre')) 74 eq('global', eval('g:amatch')) 75 eq(3, eval('g:cdprecount')) 76 eq(3, eval('g:cdcount')) 77 end) 78 79 it('DirChanged set getcwd() during event #6260', function() 80 command('lcd ' .. dirs[1]) 81 eq(dirs[1], eval('g:getcwd')) 82 83 command('tcd ' .. dirs[2]) 84 eq(dirs[2], eval('g:getcwd')) 85 86 command('cd ' .. dirs[3]) 87 eq(dirs[3], eval('g:getcwd')) 88 end) 89 90 it('disallow recursion', function() 91 command('set shellslash') 92 -- Set up a _nested_ handler. 93 command('autocmd DirChanged * nested lcd ' .. dirs[3]) 94 command('lcd ' .. dirs[1]) 95 eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev')) 96 eq(1, eval('g:cdcount')) 97 -- autocmd changed to dirs[3], but did NOT trigger another DirChanged. 98 eq(dirs[3], eval('getcwd()')) 99 end) 100 101 it('only DirChangedPre is triggered if :cd fails', function() 102 command('let g:ev = {}') 103 command('let g:cdcount = 0') 104 105 local status1, err1 = pcall(function() 106 command('lcd ' .. dirs[1] .. '/doesnotexist') 107 end) 108 eq( 109 { directory = dirs[1] .. '/doesnotexist', scope = 'window', changed_window = false }, 110 eval('g:evpre') 111 ) 112 eq({}, eval('g:ev')) 113 eq('window', eval('g:amatchpre')) 114 eq(1, eval('g:cdprecount')) 115 eq(0, eval('g:cdcount')) 116 117 local status2, err2 = pcall(function() 118 command('lcd ' .. dirs[2] .. '/doesnotexist') 119 end) 120 eq( 121 { directory = dirs[2] .. '/doesnotexist', scope = 'window', changed_window = false }, 122 eval('g:evpre') 123 ) 124 eq({}, eval('g:ev')) 125 eq('window', eval('g:amatchpre')) 126 eq(2, eval('g:cdprecount')) 127 eq(0, eval('g:cdcount')) 128 129 local status3, err3 = pcall(function() 130 command('lcd ' .. dirs[3] .. '/doesnotexist') 131 end) 132 eq( 133 { directory = dirs[3] .. '/doesnotexist', scope = 'window', changed_window = false }, 134 eval('g:evpre') 135 ) 136 eq({}, eval('g:ev')) 137 eq('window', eval('g:amatchpre')) 138 eq(3, eval('g:cdprecount')) 139 eq(0, eval('g:cdcount')) 140 141 eq(false, status1) 142 eq(false, status2) 143 eq(false, status3) 144 145 eq('E344:', string.match(err1, 'E%d*:')) 146 eq('E344:', string.match(err2, 'E%d*:')) 147 eq('E344:', string.match(err3, 'E%d*:')) 148 end) 149 150 it("are triggered by 'autochdir'", function() 151 command('set autochdir') 152 153 command('split ' .. dirs[1] .. '/foo') 154 eq({ directory = dirs[1], scope = 'window', changed_window = false }, eval('g:evpre')) 155 eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev')) 156 eq('auto', eval('g:amatchpre')) 157 eq('auto', eval('g:amatch')) 158 eq(1, eval('g:cdprecount')) 159 eq(1, eval('g:cdcount')) 160 161 command('split ' .. dirs[2] .. '/bar') 162 eq({ directory = dirs[2], scope = 'window', changed_window = false }, eval('g:evpre')) 163 eq({ cwd = dirs[2], scope = 'window', changed_window = false }, eval('g:ev')) 164 eq('auto', eval('g:amatch')) 165 eq(2, eval('g:cdprecount')) 166 eq(2, eval('g:cdcount')) 167 end) 168 169 it('do not trigger if directory has not changed', function() 170 command('lcd ' .. dirs[1]) 171 eq({ directory = dirs[1], scope = 'window', changed_window = false }, eval('g:evpre')) 172 eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev')) 173 eq('window', eval('g:amatchpre')) 174 eq('window', eval('g:amatch')) 175 eq(1, eval('g:cdprecount')) 176 eq(1, eval('g:cdcount')) 177 command('let g:evpre = {}') 178 command('let g:ev = {}') 179 command('lcd ' .. dirs[1]) 180 eq({}, eval('g:evpre')) 181 eq({}, eval('g:ev')) 182 eq(1, eval('g:cdprecount')) 183 eq(1, eval('g:cdcount')) 184 185 if is_os('win') then 186 command('lcd ' .. win_dirs[1]) 187 eq({}, eval('g:evpre')) 188 eq({}, eval('g:ev')) 189 eq(1, eval('g:cdprecount')) 190 eq(1, eval('g:cdcount')) 191 end 192 193 command('tcd ' .. dirs[2]) 194 eq({ directory = dirs[2], scope = 'tabpage', changed_window = false }, eval('g:evpre')) 195 eq({ cwd = dirs[2], scope = 'tabpage', changed_window = false }, eval('g:ev')) 196 eq('tabpage', eval('g:amatchpre')) 197 eq('tabpage', eval('g:amatch')) 198 eq(2, eval('g:cdprecount')) 199 eq(2, eval('g:cdcount')) 200 command('let g:evpre = {}') 201 command('let g:ev = {}') 202 command('tcd ' .. dirs[2]) 203 eq({}, eval('g:evpre')) 204 eq({}, eval('g:ev')) 205 eq(2, eval('g:cdprecount')) 206 eq(2, eval('g:cdcount')) 207 208 if is_os('win') then 209 command('tcd ' .. win_dirs[2]) 210 eq({}, eval('g:evpre')) 211 eq({}, eval('g:ev')) 212 eq(2, eval('g:cdprecount')) 213 eq(2, eval('g:cdcount')) 214 end 215 216 command('cd ' .. dirs[3]) 217 eq({ directory = dirs[3], scope = 'global', changed_window = false }, eval('g:evpre')) 218 eq({ cwd = dirs[3], scope = 'global', changed_window = false }, eval('g:ev')) 219 eq('global', eval('g:amatch')) 220 eq(3, eval('g:cdprecount')) 221 eq(3, eval('g:cdcount')) 222 command('let g:evpre = {}') 223 command('let g:ev = {}') 224 command('cd ' .. dirs[3]) 225 eq({}, eval('g:evpre')) 226 eq({}, eval('g:ev')) 227 eq(3, eval('g:cdprecount')) 228 eq(3, eval('g:cdcount')) 229 230 if is_os('win') then 231 command('cd ' .. win_dirs[3]) 232 eq({}, eval('g:evpre')) 233 eq({}, eval('g:ev')) 234 eq(3, eval('g:cdprecount')) 235 eq(3, eval('g:cdcount')) 236 end 237 238 command('set autochdir') 239 240 command('split ' .. dirs[1] .. '/foo') 241 eq({ directory = dirs[1], scope = 'window', changed_window = false }, eval('g:evpre')) 242 eq({ cwd = dirs[1], scope = 'window', changed_window = false }, eval('g:ev')) 243 eq('auto', eval('g:amatchpre')) 244 eq('auto', eval('g:amatch')) 245 eq(4, eval('g:cdprecount')) 246 eq(4, eval('g:cdcount')) 247 command('let g:evpre = {}') 248 command('let g:ev = {}') 249 command('split ' .. dirs[1] .. '/bar') 250 eq({}, eval('g:evpre')) 251 eq({}, eval('g:ev')) 252 eq(4, eval('g:cdprecount')) 253 eq(4, eval('g:cdcount')) 254 255 if is_os('win') then 256 command('split ' .. win_dirs[1] .. '/baz') 257 eq({}, eval('g:evpre')) 258 eq({}, eval('g:ev')) 259 eq(4, eval('g:cdprecount')) 260 eq(4, eval('g:cdcount')) 261 end 262 end) 263 264 it('are triggered by switching to win/tab with different CWD #6054', function() 265 command('lcd ' .. dirs[3]) -- window 3 266 command('split ' .. dirs[2] .. '/foo') -- window 2 267 command('lcd ' .. dirs[2]) 268 command('split ' .. dirs[1] .. '/bar') -- window 1 269 command('lcd ' .. dirs[1]) 270 271 command('2wincmd w') -- window 2 272 eq({ directory = dirs[2], scope = 'window', changed_window = true }, eval('g:evpre')) 273 eq({ cwd = dirs[2], scope = 'window', changed_window = true }, eval('g:ev')) 274 eq('window', eval('g:amatchpre')) 275 eq('window', eval('g:amatch')) 276 277 eq(4, eval('g:cdprecount')) 278 eq(4, eval('g:cdcount')) 279 command('tabnew') -- tab 2 (tab-local CWD) 280 eq(4, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 281 eq(4, eval('g:cdcount')) -- same CWD, no DirChanged event 282 command('tcd ' .. dirs[3]) 283 command('tabnext') -- tab 1 (no tab-local CWD) 284 eq({ directory = dirs[2], scope = 'window', changed_window = true }, eval('g:evpre')) 285 eq({ cwd = dirs[2], scope = 'window', changed_window = true }, eval('g:ev')) 286 eq('window', eval('g:amatchpre')) 287 eq('window', eval('g:amatch')) 288 command('tabnext') -- tab 2 289 eq({ directory = dirs[3], scope = 'tabpage', changed_window = true }, eval('g:evpre')) 290 eq({ cwd = dirs[3], scope = 'tabpage', changed_window = true }, eval('g:ev')) 291 eq('tabpage', eval('g:amatchpre')) 292 eq('tabpage', eval('g:amatch')) 293 eq(7, eval('g:cdprecount')) 294 eq(7, eval('g:cdcount')) 295 296 command('tabnext') -- tab 1 297 command('3wincmd w') -- window 3 298 eq(9, eval('g:cdprecount')) 299 eq(9, eval('g:cdcount')) 300 command('tabnext') -- tab 2 (has the *same* CWD) 301 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 302 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 303 304 if is_os('win') then 305 command('tabnew') -- tab 3 306 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 307 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 308 command('tcd ' .. win_dirs[3]) 309 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 310 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 311 command('tabnext') -- tab 1 312 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 313 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 314 command('tabprevious') -- tab 3 315 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 316 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 317 command('tabprevious') -- tab 2 318 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 319 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 320 command('tabprevious') -- tab 1 321 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 322 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 323 command('lcd ' .. win_dirs[3]) -- window 3 324 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 325 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 326 command('tabnext') -- tab 2 327 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 328 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 329 command('tabnext') -- tab 3 330 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 331 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 332 command('tabnext') -- tab 1 333 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 334 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 335 command('tabprevious') -- tab 3 336 eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event 337 eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event 338 end 339 end) 340 341 it('are triggered by nvim_set_current_dir()', function() 342 request('nvim_set_current_dir', dirs[1]) 343 eq({ directory = dirs[1], scope = 'global', changed_window = false }, eval('g:evpre')) 344 eq({ cwd = dirs[1], scope = 'global', changed_window = false }, eval('g:ev')) 345 eq(1, eval('g:cdprecount')) 346 eq(1, eval('g:cdcount')) 347 348 request('nvim_set_current_dir', dirs[2]) 349 eq({ directory = dirs[2], scope = 'global', changed_window = false }, eval('g:evpre')) 350 eq({ cwd = dirs[2], scope = 'global', changed_window = false }, eval('g:ev')) 351 eq(2, eval('g:cdprecount')) 352 eq(2, eval('g:cdcount')) 353 354 eq( 355 'Vim:E344: Can\'t find directory "/doesnotexist" in cdpath', 356 t.pcall_err(request, 'nvim_set_current_dir', '/doesnotexist') 357 ) 358 eq({ directory = '/doesnotexist', scope = 'global', changed_window = false }, eval('g:evpre')) 359 eq(3, eval('g:cdprecount')) 360 eq(2, eval('g:cdcount')) 361 end) 362 363 it('work when local to buffer', function() 364 command('let g:triggeredpre = 0') 365 command('let g:triggered = 0') 366 command('autocmd DirChangedPre <buffer> let g:triggeredpre = 1') 367 command('autocmd DirChanged <buffer> let g:triggered = 1') 368 command('cd ' .. dirs[1]) 369 eq(1, eval('g:triggeredpre')) 370 eq(1, eval('g:triggered')) 371 end) 372 end)