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)
002bc79991
This commit is contained in:
zeertzjq 2021-10-17 22:04:53 +08:00
parent 34cfe74568
commit 60584c0245
5 changed files with 132 additions and 18 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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. */