mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	feat(events): add DirChangedPre
In Nvim, like DirChanged, this also triggers when switching windows.
This marks Vim patch 8.2.4335 as ported.
vim-patch:8.2.4335: no autocommand event triggered before changing directory
Problem:    No autocommand event triggered before changing directory. (Ronnie
            Magatti)
Solution:   Add DirChangedPre. (closes vim/vim#9721)
28e8f73ae2
			
			
This commit is contained in:
		@@ -530,6 +530,17 @@ DirChanged			After the |current-directory| was changed.
 | 
			
		||||
				    changed_window: v:true if we fired the event
 | 
			
		||||
				                    switching window (or tab)
 | 
			
		||||
				<afile> is set to the new directory name.
 | 
			
		||||
				Non-recursive (event cannot trigger itself).
 | 
			
		||||
							*DirChangedPre*
 | 
			
		||||
DirChangedPre			When the |current-directory| is going to be
 | 
			
		||||
				changed, as with |DirChanged|.
 | 
			
		||||
				The pattern is like with |DirChanged|.
 | 
			
		||||
				Sets these |v:event| keys:
 | 
			
		||||
				    directory:      new working directory
 | 
			
		||||
				    scope:          "global", "tabpage", "window"
 | 
			
		||||
				    changed_window: v:true if we fired the event
 | 
			
		||||
				                    switching window (or tab)
 | 
			
		||||
				<afile> is set to the new directory name.
 | 
			
		||||
				Non-recursive (event cannot trigger itself).
 | 
			
		||||
							*FileAppendCmd*
 | 
			
		||||
FileAppendCmd			Before appending to a file.  Should do the
 | 
			
		||||
 
 | 
			
		||||
@@ -433,7 +433,8 @@ Vimscript compatibility:
 | 
			
		||||
  `this_session` does not alias to |v:this_session|
 | 
			
		||||
 | 
			
		||||
Working directory (Vim implemented some of these later than Nvim):
 | 
			
		||||
- |DirChanged| can be triggered when switching to another window.
 | 
			
		||||
- |DirChanged| and |DirChangedPre| can be triggered when switching to another
 | 
			
		||||
  window or tab.
 | 
			
		||||
- |getcwd()| and |haslocaldir()| may throw errors if the tab page or window
 | 
			
		||||
  cannot be found.  *E5000* *E5001* *E5002*
 | 
			
		||||
- |haslocaldir()| checks for tab-local directory if and only if -1 is passed as
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ return {
 | 
			
		||||
    'DiagnosticChanged',      -- diagnostics in a buffer were modified
 | 
			
		||||
    'DiffUpdated',            -- diffs have been updated
 | 
			
		||||
    'DirChanged',             -- directory changed
 | 
			
		||||
    'DirChangedPre',          -- directory is going to change
 | 
			
		||||
    'EncodingChanged',        -- after changing the 'encoding' option
 | 
			
		||||
    'ExitPre',                -- before exiting
 | 
			
		||||
    'FileAppendCmd',          -- append to a file using command
 | 
			
		||||
@@ -132,18 +133,14 @@ return {
 | 
			
		||||
  nvim_specific = {
 | 
			
		||||
    BufModifiedSet=true,
 | 
			
		||||
    DiagnosticChanged=true,
 | 
			
		||||
    DirChanged=true,
 | 
			
		||||
    RecordingEnter=true,
 | 
			
		||||
    RecordingLeave=true,
 | 
			
		||||
    Signal=true,
 | 
			
		||||
    TabClosed=true,
 | 
			
		||||
    TabNew=true,
 | 
			
		||||
    TabNewEntered=true,
 | 
			
		||||
    TermClose=true,
 | 
			
		||||
    TermOpen=true,
 | 
			
		||||
    UIEnter=true,
 | 
			
		||||
    UILeave=true,
 | 
			
		||||
    WinClosed=true,
 | 
			
		||||
    WinScrolled=true,
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1517,13 +1517,13 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
 | 
			
		||||
        || event == EVENT_CMDLINELEAVE || event == EVENT_CMDWINENTER
 | 
			
		||||
        || event == EVENT_CMDWINLEAVE || event == EVENT_CMDUNDEFINED
 | 
			
		||||
        || event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
 | 
			
		||||
        || event == EVENT_DIRCHANGED || event == EVENT_FILETYPE
 | 
			
		||||
        || event == EVENT_FUNCUNDEFINED || event == EVENT_MODECHANGED
 | 
			
		||||
        || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST
 | 
			
		||||
        || event == EVENT_QUICKFIXCMDPRE || event == EVENT_REMOTEREPLY
 | 
			
		||||
        || event == EVENT_SPELLFILEMISSING || event == EVENT_SYNTAX
 | 
			
		||||
        || event == EVENT_SIGNAL || event == EVENT_TABCLOSED
 | 
			
		||||
        || event == EVENT_WINCLOSED) {
 | 
			
		||||
        || event == EVENT_DIRCHANGED || event == EVENT_DIRCHANGEDPRE
 | 
			
		||||
        || event == EVENT_FILETYPE || event == EVENT_FUNCUNDEFINED
 | 
			
		||||
        || event == EVENT_MODECHANGED || event == EVENT_OPTIONSET
 | 
			
		||||
        || event == EVENT_QUICKFIXCMDPOST || event == EVENT_QUICKFIXCMDPRE
 | 
			
		||||
        || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING
 | 
			
		||||
        || event == EVENT_SYNTAX || event == EVENT_SIGNAL
 | 
			
		||||
        || event == EVENT_TABCLOSED || event == EVENT_WINCLOSED) {
 | 
			
		||||
      fname = vim_strsave(fname);
 | 
			
		||||
    } else {
 | 
			
		||||
      fname = (char_u *)FullName_save((char *)fname, false);
 | 
			
		||||
 
 | 
			
		||||
@@ -7784,7 +7784,7 @@ static char_u *get_prevdir(CdScope scope)
 | 
			
		||||
/// Deal with the side effects of changing the current directory.
 | 
			
		||||
///
 | 
			
		||||
/// @param scope  Scope of the function call (global, tab or window).
 | 
			
		||||
void post_chdir(CdScope scope, bool trigger_dirchanged)
 | 
			
		||||
static void post_chdir(CdScope scope, bool trigger_dirchanged)
 | 
			
		||||
{
 | 
			
		||||
  // Always overwrite the window-local CWD.
 | 
			
		||||
  XFREE_CLEAR(curwin->w_localdir);
 | 
			
		||||
@@ -7825,7 +7825,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
 | 
			
		||||
  shorten_fnames(true);
 | 
			
		||||
 | 
			
		||||
  if (trigger_dirchanged) {
 | 
			
		||||
    do_autocmd_dirchanged(cwd, scope, kCdCauseManual);
 | 
			
		||||
    do_autocmd_dirchanged(cwd, scope, kCdCauseManual, false);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -7869,11 +7869,14 @@ bool changedir_func(char_u *new_dir, CdScope scope)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool dir_differs = pdir == NULL || pathcmp((char *)pdir, (char *)new_dir, -1) != 0;
 | 
			
		||||
  if (dir_differs && vim_chdir(new_dir) != 0) {
 | 
			
		||||
  if (dir_differs) {
 | 
			
		||||
    do_autocmd_dirchanged((char *)new_dir, scope, kCdCauseManual, true);
 | 
			
		||||
    if (vim_chdir(new_dir) != 0) {
 | 
			
		||||
      emsg(_(e_failed));
 | 
			
		||||
      xfree(pdir);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  char_u **pp;
 | 
			
		||||
  switch (scope) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1600,11 +1600,13 @@ theend:
 | 
			
		||||
  return file_name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
 | 
			
		||||
void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause, bool pre)
 | 
			
		||||
{
 | 
			
		||||
  static bool recursive = false;
 | 
			
		||||
 | 
			
		||||
  if (recursive || !has_event(EVENT_DIRCHANGED)) {
 | 
			
		||||
  event_T event = pre ? EVENT_DIRCHANGEDPRE : EVENT_DIRCHANGED;
 | 
			
		||||
 | 
			
		||||
  if (recursive || !has_event(event)) {
 | 
			
		||||
    // No autocommand was defined or we changed
 | 
			
		||||
    // the directory from this autocommand.
 | 
			
		||||
    return;
 | 
			
		||||
@@ -1638,8 +1640,12 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
 | 
			
		||||
  new_dir = new_dir_buf;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  tv_dict_add_str(dict, S_LEN("scope"), buf);  // -V614
 | 
			
		||||
  if (pre) {
 | 
			
		||||
    tv_dict_add_str(dict, S_LEN("directory"), new_dir);
 | 
			
		||||
  } else {
 | 
			
		||||
    tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
 | 
			
		||||
  }
 | 
			
		||||
  tv_dict_add_str(dict, S_LEN("scope"), buf);  // -V614
 | 
			
		||||
  tv_dict_add_bool(dict, S_LEN("changed_window"), cause == kCdCauseWindow);
 | 
			
		||||
  tv_dict_set_keys_readonly(dict);
 | 
			
		||||
 | 
			
		||||
@@ -1655,8 +1661,7 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
 | 
			
		||||
    abort();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
 | 
			
		||||
                 curbuf);
 | 
			
		||||
  apply_autocmds(event, (char_u *)buf, (char_u *)new_dir, false, curbuf);
 | 
			
		||||
 | 
			
		||||
  restore_v_event(dict, &save_v_event);
 | 
			
		||||
 | 
			
		||||
@@ -1682,12 +1687,16 @@ int vim_chdirfile(char_u *fname, CdCause cause)
 | 
			
		||||
    return OK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (cause != kCdCauseOther) {
 | 
			
		||||
    do_autocmd_dirchanged(dir, kCdScopeWindow, cause, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (os_chdir(dir) != 0) {
 | 
			
		||||
    return FAIL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (cause != kCdCauseOther) {
 | 
			
		||||
    do_autocmd_dirchanged(dir, kCdScopeWindow, cause);
 | 
			
		||||
    do_autocmd_dirchanged(dir, kCdScopeWindow, cause, false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return OK;
 | 
			
		||||
 
 | 
			
		||||
@@ -1850,14 +1850,16 @@ endfunc
 | 
			
		||||
 | 
			
		||||
function Test_dirchanged_global()
 | 
			
		||||
  call s:Before_test_dirchanged()
 | 
			
		||||
  autocmd test_dirchanged DirChangedPre global call add(s:li, "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)
 | 
			
		||||
  call assert_equal(["cd:", s:dir_foo], s:li)
 | 
			
		||||
  let expected = ["pre cd " .. s:dir_foo, "cd:", s:dir_foo]
 | 
			
		||||
  call assert_equal(expected, s:li)
 | 
			
		||||
  call chdir(s:dir_foo)
 | 
			
		||||
  call assert_equal(["cd:", s:dir_foo], s:li)
 | 
			
		||||
  call assert_equal(expected, s:li)
 | 
			
		||||
  exe 'lcd ' .. fnameescape(s:dir_bar)
 | 
			
		||||
  call assert_equal(["cd:", s:dir_foo], s:li)
 | 
			
		||||
  call assert_equal(expected, s:li)
 | 
			
		||||
  call s:After_test_dirchanged()
 | 
			
		||||
endfunc
 | 
			
		||||
 | 
			
		||||
@@ -1879,6 +1881,7 @@ 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
 | 
			
		||||
@@ -1886,7 +1889,8 @@ function Test_dirchanged_auto()
 | 
			
		||||
  call assert_equal([], s:li)
 | 
			
		||||
  exe 'edit ' . s:dir_foo . '/Xfile'
 | 
			
		||||
  call assert_equal(s:dir_foo, getcwd())
 | 
			
		||||
  call assert_equal(["auto:", s:dir_foo], s:li)
 | 
			
		||||
  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()
 | 
			
		||||
 
 | 
			
		||||
@@ -4645,20 +4645,29 @@ void fix_current_dir(void)
 | 
			
		||||
        globaldir = (char_u *)xstrdup(cwd);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    bool dir_differs = pathcmp(new_dir, cwd, -1) != 0;
 | 
			
		||||
    if (!p_acd && dir_differs) {
 | 
			
		||||
      do_autocmd_dirchanged(new_dir, curwin->w_localdir ? kCdScopeWindow : kCdScopeTabpage,
 | 
			
		||||
                            kCdCauseWindow, true);
 | 
			
		||||
    }
 | 
			
		||||
    if (os_chdir(new_dir) == 0) {
 | 
			
		||||
      if (!p_acd && pathcmp(new_dir, cwd, -1) != 0) {
 | 
			
		||||
        do_autocmd_dirchanged(new_dir, curwin->w_localdir
 | 
			
		||||
                              ? kCdScopeWindow : kCdScopeTabpage, kCdCauseWindow);
 | 
			
		||||
      if (!p_acd && dir_differs) {
 | 
			
		||||
        do_autocmd_dirchanged(new_dir, curwin->w_localdir ? kCdScopeWindow : kCdScopeTabpage,
 | 
			
		||||
                              kCdCauseWindow, false);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    last_chdir_reason = NULL;
 | 
			
		||||
    shorten_fnames(true);
 | 
			
		||||
    }
 | 
			
		||||
  } else if (globaldir != NULL) {
 | 
			
		||||
    // Window doesn't have a local directory and we are not in the global
 | 
			
		||||
    // directory: Change to the global directory.
 | 
			
		||||
    bool dir_differs = pathcmp((char *)globaldir, cwd, -1) != 0;
 | 
			
		||||
    if (!p_acd && dir_differs) {
 | 
			
		||||
      do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow, true);
 | 
			
		||||
    }
 | 
			
		||||
    if (os_chdir((char *)globaldir) == 0) {
 | 
			
		||||
      if (!p_acd && pathcmp((char *)globaldir, cwd, -1) != 0) {
 | 
			
		||||
        do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow);
 | 
			
		||||
      if (!p_acd && dir_differs) {
 | 
			
		||||
        do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow, false);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    XFREE_CLEAR(globaldir);
 | 
			
		||||
 
 | 
			
		||||
@@ -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')]])
 | 
			
		||||
  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)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user