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 #4362)
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index f33ffb9..fae7118 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1326,6 +1326,10 @@
*:tch* *:tchdir*
:tch[dir][!] Same as |:tcd|.
+ *:tcd-*
+:tcd[!] - Change to the previous current directory, before the
+ last ":tcd {path}" command.
+
*:lc* *:lcd*
:lc[d][!] {path} Like |:cd|, but only set the current directory when
the cursor is in the current window. The current
@@ -1335,6 +1339,10 @@
*:lch* *:lchdir*
:lch[dir][!] Same as |:lcd|.
+ *:lcd-*
+:lcd[!] - Change to the previous current directory, before the
+ last ":lcd {path}" command.
+
*:pw* *:pwd* *E187*
:pw[d] Print the current directory name.
Also see |getcwd()|.
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index a98dc07..3a1a614 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -6582,6 +6582,19 @@
#endif
/*
+ * Get the previous directory for the given chdir scope.
+ */
+ static char_u *
+get_prevdir(cdscope_T scope)
+{
+ if (scope == CDSCOPE_WINDOW)
+ return curwin->w_prevdir;
+ else if (scope == CDSCOPE_TABPAGE)
+ return curtab->tp_prevdir;
+ return prev_dir;
+}
+
+/*
* Deal with the side effects of changing the current directory.
* When 'scope' is CDSCOPE_TABPAGE then this was after an ":tcd" command.
* When 'scope' is CDSCOPE_WINDOW then this was after an ":lcd" command.
@@ -6595,10 +6608,13 @@
VIM_CLEAR(curwin->w_localdir);
if (scope != CDSCOPE_GLOBAL)
{
- // If still in global directory, need to remember current
- // directory as global directory.
- if (globaldir == NULL && prev_dir != NULL)
- globaldir = vim_strsave(prev_dir);
+ char_u *pdir = get_prevdir(scope);
+
+ // If still in the global directory, need to remember current
+ // directory as the global directory.
+ if (globaldir == NULL && pdir != NULL)
+ globaldir = vim_strsave(pdir);
+
// Remember this local directory for the window.
if (mch_dirname(NameBuff, MAXPATHL) == OK)
{
@@ -6610,8 +6626,7 @@
}
else
{
- // We are now in the global directory, no need to remember its
- // name.
+ // We are now in the global directory, no need to remember its name.
VIM_CLEAR(globaldir);
}
@@ -6633,6 +6648,7 @@
cdscope_T scope)
{
char_u *tofree;
+ char_u *pdir = NULL;
int dir_differs;
int retval = FALSE;
@@ -6648,20 +6664,29 @@
// ":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;
}
+ // Free the previous directory
+ tofree = get_prevdir(scope);
+
// Save current directory for next ":cd -"
- tofree = prev_dir;
if (mch_dirname(NameBuff, MAXPATHL) == OK)
- prev_dir = vim_strsave(NameBuff);
+ pdir = vim_strsave(NameBuff);
else
- prev_dir = NULL;
+ pdir = NULL;
+ if (scope == CDSCOPE_WINDOW)
+ curwin->w_prevdir = pdir;
+ else if (scope == CDSCOPE_TABPAGE)
+ curtab->tp_prevdir = pdir;
+ else
+ prev_dir = pdir;
#if defined(UNIX) || defined(VMS)
// for UNIX ":cd" means: go to home directory
@@ -6682,8 +6707,8 @@
new_dir = NameBuff;
}
#endif
- dir_differs = new_dir == NULL || prev_dir == NULL
- || pathcmp((char *)prev_dir, (char *)new_dir, -1) != 0;
+ dir_differs = new_dir == NULL || pdir == NULL
+ || pathcmp((char *)pdir, (char *)new_dir, -1) != 0;
if (new_dir == NULL || (dir_differs && vim_chdir(new_dir)))
emsg(_(e_failed));
else
diff --git a/src/filepath.c b/src/filepath.c
index ad7b8b0..8bc941d 100644
--- a/src/filepath.c
+++ b/src/filepath.c
@@ -726,6 +726,7 @@
if (argvars[0].v_type != VAR_STRING)
// Returning an empty string means it failed.
+ // No error message, for historic reasons.
return;
// Return the current directory
diff --git a/src/structs.h b/src/structs.h
index 8fb14d7..80b7cff 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -2994,6 +2994,8 @@
char_u *tp_localdir; // absolute path of local directory or
// NULL
+ char_u *tp_prevdir; // previous directory
+
#ifdef FEAT_DIFF
diff_T *tp_first_diff;
buf_T *(tp_diffbuf[DB_COUNT]);
@@ -3397,6 +3399,7 @@
char_u *w_localdir; // absolute path of local directory or
// NULL
+ char_u *w_prevdir; // previous directory
#ifdef FEAT_MENU
vimmenu_T *w_winbar; // The root of the WinBar menu hierarchy.
winbar_item_T *w_winbar_items; // list of items in the WinBar
diff --git a/src/testdir/test_cd.vim b/src/testdir/test_cd.vim
index ad25f3a..53f9c10 100644
--- a/src/testdir/test_cd.vim
+++ b/src/testdir/test_cd.vim
@@ -129,6 +129,69 @@
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_completion()
call mkdir('XComplDir1', 'p')
call mkdir('XComplDir2', 'p')
diff --git a/src/version.c b/src/version.c
index 20c0e0d..5fca34b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 909,
+/**/
908,
/**/
907,
diff --git a/src/window.c b/src/window.c
index ede2c6f..931d86b 100644
--- a/src/window.c
+++ b/src/window.c
@@ -3809,6 +3809,7 @@
#endif
vim_free(tp->tp_localdir);
+ vim_free(tp->tp_prevdir);
#ifdef FEAT_PYTHON
python_tabpage_free(tp);
@@ -4974,6 +4975,7 @@
vim_free(wp->w_tagstack[i].user_data);
}
vim_free(wp->w_localdir);
+ vim_free(wp->w_prevdir);
// Remove the window from the b_wininfo lists, it may happen that the
// freed memory is re-used for another window.