# HG changeset patch # User Bram Moolenaar # Date 1591389904 -7200 # Node ID d91b8d1e5198a181f1fc9fcc6a6614ba584599dd # Parent 24fa685e72e9f4d4cc0f50d7f5d7df6be75af54d patch 8.2.0909: cannot go back to the previous local directory Commit: https://github.com/vim/vim/commit/002bc79991286934a9593b80635c27d4238cdfc4 Author: Bram Moolenaar Date: Fri Jun 5 22:33:42 2020 +0200 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 https://github.com/vim/vim/issues/4362) diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -1326,6 +1326,10 @@ present in 'cpoptions' and "!" is not us *: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 @@ present in 'cpoptions' and "!" is not us *: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 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -6582,6 +6582,19 @@ free_cd_dir(void) #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 @@ post_chdir(cdscope_T scope) 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 @@ post_chdir(cdscope_T scope) } 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 @@ changedir_func( cdscope_T scope) { char_u *tofree; + char_u *pdir = NULL; int dir_differs; int retval = FALSE; @@ -6648,20 +6664,29 @@ changedir_func( // ":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 @@ changedir_func( 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 --- a/src/filepath.c +++ b/src/filepath.c @@ -726,6 +726,7 @@ f_chdir(typval_T *argvars, typval_T *ret 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 --- a/src/structs.h +++ b/src/structs.h @@ -2994,6 +2994,8 @@ struct tabpage_S 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 @@ struct window_S 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 --- a/src/testdir/test_cd.vim +++ b/src/testdir/test_cd.vim @@ -129,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_completion() call mkdir('XComplDir1', 'p') call mkdir('XComplDir2', 'p') diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 909, +/**/ 908, /**/ 907, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -3809,6 +3809,7 @@ free_tabpage(tabpage_T *tp) #endif vim_free(tp->tp_localdir); + vim_free(tp->tp_prevdir); #ifdef FEAT_PYTHON python_tabpage_free(tp); @@ -4974,6 +4975,7 @@ win_free( 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.