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
commit60584c0245a55d72422686aa702132814145b0c1 (patch)
tree0bb558f11c5bd9e5bb0b4a51ea77530899767dd7
parent34cfe745681189bbd8ec2543971a49e013bfebf9 (diff)
downloadrneovim-60584c0245a55d72422686aa702132814145b0c1.tar.gz
rneovim-60584c0245a55d72422686aa702132814145b0c1.tar.bz2
rneovim-60584c0245a55d72422686aa702132814145b0c1.zip
vim-patch:8.2.0909: cannot go back to the previous local directory
Problem: Cannot go back to the previous local directory. Solution: Add "tcd -" and "lcd -". (Yegappan Lakshmanan, closes vim/vim#4362) https://github.com/vim/vim/commit/002bc79991286934a9593b80635c27d4238cdfc4
-rw-r--r--src/nvim/buffer_defs.h5
-rw-r--r--src/nvim/ex_docmd.c56
-rw-r--r--src/nvim/file_search.c10
-rw-r--r--src/nvim/testdir/test_cd.vim77
-rw-r--r--src/nvim/window.c2
5 files changed, 132 insertions, 18 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 2c411553b8..19b0a3c5c6 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -953,6 +953,7 @@ struct tabpage_S {
ScopeDictDictItem tp_winvar; ///< Variable for "t:" Dictionary.
dict_T *tp_vars; ///< Internal variables, local to tab page.
char_u *tp_localdir; ///< Absolute path of local cwd or NULL.
+ char_u *tp_prevdir; ///< Previous directory.
};
/*
@@ -1381,8 +1382,8 @@ struct window_S {
// out of range!)
int w_arg_idx_invalid; // editing another file than w_arg_idx
- char_u *w_localdir; /* absolute path of local directory or
- NULL */
+ char_u *w_localdir; // absolute path of local directory or NULL
+ char_u *w_prevdir; // previous directory
// Options local to a window.
// They are local because they influence the layout of the window or
// depend on the window layout.
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 06e94fea99..26c06b2675 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -7707,6 +7707,21 @@ void free_cd_dir(void)
#endif
+// Get the previous directory for the given chdir scope.
+static char_u *get_prevdir(CdScope scope)
+{
+ switch (scope) {
+ case kCdScopeTab:
+ return curtab->tp_prevdir;
+ break;
+ case kCdScopeWindow:
+ return curwin->w_prevdir;
+ break;
+ default:
+ return prev_dir;
+ }
+}
+
/// Deal with the side effects of changing the current directory.
///
/// @param scope Scope of the function call (global, tab or window).
@@ -7721,9 +7736,10 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
}
if (scope < kCdScopeGlobal) {
+ char_u *pdir = get_prevdir(scope);
// If still in global directory, set CWD as the global directory.
- if (globaldir == NULL && prev_dir != NULL) {
- globaldir = vim_strsave(prev_dir);
+ if (globaldir == NULL && pdir != NULL) {
+ globaldir = vim_strsave(pdir);
}
}
@@ -7754,10 +7770,13 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
}
/// Change directory function used by :cd/:tcd/:lcd Ex commands and the chdir() function.
+/// @param new_dir The directory to change to.
+/// @param scope Scope of the function call (global, tab or window).
/// @return true if the directory is successfully changed.
bool changedir_func(char_u *new_dir, CdScope scope)
{
char_u *tofree;
+ char_u *pdir = NULL;
bool retval = false;
if (new_dir == NULL || allbuf_locked()) {
@@ -7766,19 +7785,32 @@ bool changedir_func(char_u *new_dir, CdScope scope)
// ":cd -": Change to previous directory
if (STRCMP(new_dir, "-") == 0) {
- if (prev_dir == NULL) {
+ pdir = get_prevdir(scope);
+ if (pdir == NULL) {
EMSG(_("E186: No previous directory"));
return false;
}
- new_dir = prev_dir;
+ new_dir = pdir;
}
- // Save current directory for next ":cd -"
- tofree = prev_dir;
+ // Free the previous directory
+ tofree = get_prevdir(scope);
+
if (os_dirname(NameBuff, MAXPATHL) == OK) {
- prev_dir = vim_strsave(NameBuff);
+ pdir = vim_strsave(NameBuff);
} else {
- prev_dir = NULL;
+ pdir = NULL;
+ }
+
+ switch (scope) {
+ case kCdScopeTab:
+ curtab->tp_prevdir = pdir;
+ break;
+ case kCdScopeWindow:
+ curwin->w_prevdir = pdir;
+ break;
+ default:
+ prev_dir = pdir;
}
#if defined(UNIX)
@@ -7790,12 +7822,12 @@ bool changedir_func(char_u *new_dir, CdScope scope)
}
#endif
- bool dir_differs = prev_dir == NULL || pathcmp((char *)prev_dir, (char *)new_dir, -1) != 0;
- if (dir_differs && vim_chdir(new_dir)) {
- EMSG(_(e_failed));
- } else {
+ if (vim_chdir(new_dir) == 0) {
+ bool dir_differs = pdir == NULL || pathcmp((char *)pdir, (char *)new_dir, -1) != 0;
post_chdir(scope, dir_differs);
retval = true;
+ } else {
+ EMSG(_(e_failed));
}
xfree(tofree);
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 22c7b35fa9..0922017e2b 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -54,6 +54,7 @@
#include "nvim/eval.h"
#include "nvim/file_search.h"
#include "nvim/fileio.h"
+#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
@@ -1666,11 +1667,12 @@ int vim_chdirfile(char_u *fname, CdCause cause)
NameBuff[0] = NUL;
}
- if (cause != kCdCauseOther && pathcmp(dir, (char *)NameBuff, -1) != 0) {
- if (os_chdir(dir) != 0) {
- return FAIL;
+ if (os_chdir(dir) == 0) {
+ if (cause != kCdCauseOther && pathcmp(dir, (char *)NameBuff, -1) != 0) {
+ do_autocmd_dirchanged(dir, kCdScopeWindow, cause);
}
- do_autocmd_dirchanged(dir, kCdScopeWindow, cause);
+ } else {
+ return FAIL;
}
return OK;
diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim
index c6eda58284..36135b52ce 100644
--- a/src/nvim/testdir/test_cd.vim
+++ b/src/nvim/testdir/test_cd.vim
@@ -43,6 +43,20 @@ func Test_cd_minus()
call assert_equal(path_dotdot, getcwd())
cd -
call assert_equal(path, getcwd())
+
+ " Test for :cd - without a previous directory
+ let lines =<< trim [SCRIPT]
+ call assert_fails('cd -', 'E186:')
+ call assert_fails('call chdir("-")', 'E186:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
endfunc
func Test_cd_with_cpo_chdir()
@@ -115,6 +129,69 @@ func Test_chdir_func()
call delete('Xdir', 'rf')
endfunc
+" Test for changing to the previous directory '-'
+func Test_prev_dir()
+ let topdir = getcwd()
+ call mkdir('Xdir/a/b/c', 'p')
+
+ " Create a few tabpages and windows with different directories
+ new | only
+ tabnew | new
+ tabnew
+ tabfirst
+ cd Xdir
+ tabnext | wincmd t
+ tcd a
+ wincmd w
+ lcd b
+ tabnext
+ tcd a/b/c
+
+ " Change to the previous directory twice in all the windows.
+ tabfirst
+ cd - | cd -
+ tabnext | wincmd t
+ tcd - | tcd -
+ wincmd w
+ lcd - | lcd -
+ tabnext
+ tcd - | tcd -
+
+ " Check the directory of all the windows
+ tabfirst
+ call assert_equal('Xdir', fnamemodify(getcwd(), ':t'))
+ tabnext | wincmd t
+ call assert_equal('a', fnamemodify(getcwd(), ':t'))
+ wincmd w
+ call assert_equal('b', fnamemodify(getcwd(), ':t'))
+ tabnext
+ call assert_equal('c', fnamemodify(getcwd(), ':t'))
+
+ " Change to the previous directory using chdir()
+ tabfirst
+ call chdir("-") | call chdir("-")
+ tabnext | wincmd t
+ call chdir("-") | call chdir("-")
+ wincmd w
+ call chdir("-") | call chdir("-")
+ tabnext
+ call chdir("-") | call chdir("-")
+
+ " Check the directory of all the windows
+ tabfirst
+ call assert_equal('Xdir', fnamemodify(getcwd(), ':t'))
+ tabnext | wincmd t
+ call assert_equal('a', fnamemodify(getcwd(), ':t'))
+ wincmd w
+ call assert_equal('b', fnamemodify(getcwd(), ':t'))
+ tabnext
+ call assert_equal('c', fnamemodify(getcwd(), ':t'))
+
+ only | tabonly
+ call chdir(topdir)
+ call delete('Xdir', 'rf')
+endfunc
+
func Test_cd_from_non_existing_dir()
CheckNotMSWindows
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 49d7c9c9f5..db71512a3b 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -3733,6 +3733,7 @@ void free_tabpage(tabpage_T *tp)
}
xfree(tp->tp_localdir);
+ xfree(tp->tp_prevdir);
xfree(tp);
}
@@ -4771,6 +4772,7 @@ static void win_free(win_T *wp, tabpage_T *tp)
}
xfree(wp->w_localdir);
+ xfree(wp->w_prevdir);
/* Remove the window from the b_wininfo lists, it may happen that the
* freed memory is re-used for another window. */