aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2021-10-17 22:04:53 +0800
committerzeertzjq <zeertzjq@outlook.com>2021-10-17 22:04:53 +0800
commit920473d2f228fb33c63c092c825b182a7434f25f (patch)
tree66286a9b6d460810d0d9d596f593c501a953be2c
parent30af69509dc91552dc41451857b18907f018c1bd (diff)
downloadrneovim-920473d2f228fb33c63c092c825b182a7434f25f.tar.gz
rneovim-920473d2f228fb33c63c092c825b182a7434f25f.tar.bz2
rneovim-920473d2f228fb33c63c092c825b182a7434f25f.zip
vim-patch:8.0.1459: cannot handle change of directory
Problem: Cannot handle change of directory. Solution: Add the DirChanged autocommand event. (Andy Massimino, closes vim/vim#888) Avoid changing directory for 'autochdir' too often. https://github.com/vim/vim/commit/b7407d3fc9496f9048fb65ab17b5ba3444965c0e Only add "auto" pattern. "window" and "global" are already implemented. Skip `Test_dirchanged_auto` using `CheckFunction test_autochdir`. Part of PR #15952. More information can be found there. N/A patches for version.c: vim-patch:8.0.1460: missing file in patch Problem: Missing file in patch. Solution: Add changes to missing file. https://github.com/vim/vim/commit/b5cb65ba2bcc6bbc6d2798a2dea18b95f0b38f5e vim-patch:8.0.1461: missing another file in patch Problem: Missing another file in patch. Solution: Add changes to missing file. https://github.com/vim/vim/commit/15833239a4131279935a4bd574b74fe3a2b0f49f
-rw-r--r--runtime/doc/autocmd.txt6
-rw-r--r--runtime/doc/vim_diff.txt1
-rw-r--r--src/nvim/buffer.c5
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/ex_session.c2
-rw-r--r--src/nvim/file_search.c24
-rw-r--r--src/nvim/globals.h8
-rw-r--r--src/nvim/testdir/test_autocmd.vim56
-rw-r--r--src/nvim/window.c4
9 files changed, 94 insertions, 14 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 5923dada43..b7df0fba54 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -519,11 +519,17 @@ DiffUpdated After diffs have been updated. Depending on
change or when doing |:diffupdate|.
*DirChanged*
DirChanged After the |current-directory| was changed.
+ The pattern can be:
+ "window" to trigger on `:lcd`
+ "tab" to trigger on `:tcd`
+ "global" to trigger on `:cd`
+ "auto" to trigger on 'autochdir'.
Sets these |v:event| keys:
cwd: current working directory
scope: "global", "tab", "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
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 64824b2e3f..c85cae4004 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -180,6 +180,7 @@ Commands:
|:match| can be invoked before highlight group is defined
Events:
+ |DirChanged| can be triggered when switching to another window
|Signal|
|TabNewEntered|
|TermClose|
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 37cc854959..386714b05a 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -593,9 +593,6 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
buf->b_nwindows--;
}
- // Change directories when the 'acd' option is set.
- do_autochdir();
-
// Disable buffer-updates for the current buffer.
// No need to check `unload_buf`: in that case the function returned above.
buf_updates_unload(buf, false);
@@ -1628,7 +1625,7 @@ void do_autochdir(void)
if (p_acd) {
if (starting == 0
&& curbuf->b_ffname != NULL
- && vim_chdirfile(curbuf->b_ffname) == OK) {
+ && vim_chdirfile(curbuf->b_ffname, kCdCauseAuto) == OK) {
post_chdir(kCdScopeGlobal, false);
shorten_fnames(true);
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 16a9b78c6a..5d83e2218b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -7749,7 +7749,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
shorten_fnames(true);
if (trigger_dirchanged) {
- do_autocmd_dirchanged(cwd, scope, false);
+ do_autocmd_dirchanged(cwd, scope, kCdCauseManual);
}
}
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 1e1da6a9a3..0dfd7e1edd 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -963,7 +963,7 @@ void ex_mkrc(exarg_T *eap)
*dirnow = NUL;
}
if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR)) {
- if (vim_chdirfile((char_u *)fname) == OK) {
+ if (vim_chdirfile((char_u *)fname, kCdCauseOther) == OK) {
shorten_fnames(true);
}
} else if (*dirnow != NUL
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 5458d8acf2..e7c4785beb 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1590,7 +1590,7 @@ theend:
return file_name;
}
-void do_autocmd_dirchanged(char *new_dir, CdScope scope, bool changed_window)
+void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
{
static bool recursive = false;
@@ -1621,10 +1621,22 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, bool changed_window)
}
tv_dict_add_str(dict, S_LEN("scope"), buf); // -V614
- tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
- tv_dict_add_bool(dict, S_LEN("changed_window"), changed_window);
+ tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
+ tv_dict_add_bool(dict, S_LEN("changed_window"), cause == kCdCauseWindow);
tv_dict_set_keys_readonly(dict);
+ switch (cause) {
+ case kCdCauseManual:
+ case kCdCauseWindow:
+ break;
+ case kCdCauseAuto:
+ snprintf(buf, sizeof(buf), "auto");
+ break;
+ case kCdCauseOther:
+ // Should never happen.
+ abort();
+ }
+
apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
curbuf);
@@ -1636,7 +1648,7 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, bool changed_window)
/// Change to a file's directory.
/// Caller must call shorten_fnames()!
/// @return OK or FAIL
-int vim_chdirfile(char_u *fname)
+int vim_chdirfile(char_u *fname, CdCause cause)
{
char dir[MAXPATHL];
@@ -1654,8 +1666,8 @@ int vim_chdirfile(char_u *fname)
#ifdef BACKSLASH_IN_FILENAME
slash_adjust((char_u *)dir);
#endif
- if (!strequal(dir, (char *)NameBuff)) {
- do_autocmd_dirchanged(dir, kCdScopeWindow, false);
+ if (cause != kCdCauseOther && !strequal(dir, (char *)NameBuff)) {
+ do_autocmd_dirchanged(dir, kCdScopeWindow, cause);
}
return OK;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 8a36b3bedd..e04856e85f 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -1042,6 +1042,14 @@ typedef enum {
#define MIN_CD_SCOPE kCdScopeWindow
#define MAX_CD_SCOPE kCdScopeGlobal
+/// What caused the current directory to change.
+typedef enum {
+ kCdCauseOther = -1,
+ kCdCauseManual, ///< Using `:cd`, `:tcd`, `:lcd` or `chdir()`.
+ kCdCauseWindow, ///< Switching to another window.
+ kCdCauseAuto, ///< On 'autochdir'.
+} CdCause;
+
// Only filled for Win32.
EXTERN char windowsVersion[20] INIT(= { 0 });
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 015979e1be..d174b11a9c 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1328,6 +1328,62 @@ func Test_autocommand_all_events()
call assert_fails('au * x bwipe', 'E1155:')
endfunc
+function s:Before_test_dirchanged()
+ augroup test_dirchanged
+ autocmd!
+ augroup END
+ let s:li = []
+ let s:dir_this = getcwd()
+ let s:dir_other = s:dir_this . '/foo'
+ call mkdir(s:dir_other)
+endfunc
+
+function s:After_test_dirchanged()
+ exe 'cd' s:dir_this
+ call delete(s:dir_other, 'd')
+ augroup test_dirchanged
+ autocmd!
+ augroup END
+endfunc
+
+function Test_dirchanged_global()
+ call s:Before_test_dirchanged()
+ autocmd test_dirchanged DirChanged global call add(s:li, "cd:")
+ autocmd test_dirchanged DirChanged global call add(s:li, expand("<afile>"))
+ exe 'cd' s:dir_other
+ call assert_equal(["cd:", s:dir_other], s:li)
+ exe 'lcd' s:dir_other
+ call assert_equal(["cd:", s:dir_other], s:li)
+ 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>"))
+ exe 'cd' s:dir_other
+ call assert_equal([], s:li)
+ exe 'lcd' s:dir_other
+ call assert_equal(["lcd:", s:dir_other], s:li)
+ call s:After_test_dirchanged()
+endfunc
+
+function Test_dirchanged_auto()
+ call s:Before_test_dirchanged()
+ call test_autochdir()
+ autocmd test_dirchanged DirChanged auto call add(s:li, "auto:")
+ autocmd test_dirchanged DirChanged auto call add(s:li, expand("<afile>"))
+ set acd
+ exe 'cd ..'
+ call assert_equal([], s:li)
+ exe 'edit ' . s:dir_other . '/Xfile'
+ call assert_equal(s:dir_other, getcwd())
+ call assert_equal(["auto:", s:dir_other], s:li)
+ set noacd
+ bwipe!
+ call s:After_test_dirchanged()
+endfunc
+
" Test TextChangedI and TextChangedP
" See test/functional/viml/completion_spec.lua'
func Test_ChangedP()
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 1fe4aa1add..a7470889b3 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -4542,7 +4542,7 @@ static void win_enter_ext(win_T *const wp, const int flags)
if (os_chdir(new_dir) == 0) {
if (!p_acd && !strequal(new_dir, cwd)) {
do_autocmd_dirchanged(new_dir, curwin->w_localdir
- ? kCdScopeWindow : kCdScopeTab, true);
+ ? kCdScopeWindow : kCdScopeTab, kCdCauseWindow);
}
shorten_fnames(true);
}
@@ -4551,7 +4551,7 @@ static void win_enter_ext(win_T *const wp, const int flags)
// directory: Change to the global directory.
if (os_chdir((char *)globaldir) == 0) {
if (!p_acd && !strequal((char *)globaldir, cwd)) {
- do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, true);
+ do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow);
}
}
XFREE_CLEAR(globaldir);