aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_docmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_docmd.c')
-rw-r--r--src/nvim/ex_docmd.c151
1 files changed, 102 insertions, 49 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 5193391442..f649266b9f 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 kCdScopeTabpage:
+ 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).
@@ -7716,14 +7731,15 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
XFREE_CLEAR(curwin->w_localdir);
// Overwrite the tab-local CWD for :cd, :tcd.
- if (scope >= kCdScopeTab) {
+ if (scope >= kCdScopeTabpage) {
XFREE_CLEAR(curtab->tp_localdir);
}
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);
}
}
@@ -7736,7 +7752,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
// We are now in the global directory, no need to remember its name.
XFREE_CLEAR(globaldir);
break;
- case kCdScopeTab:
+ case kCdScopeTabpage:
curtab->tp_localdir = (char_u *)xstrdup(cwd);
break;
case kCdScopeWindow:
@@ -7749,59 +7765,92 @@ 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);
}
}
-/// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`.
-void ex_cd(exarg_T *eap)
+/// 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 *new_dir;
char_u *tofree;
+ char_u *pdir = NULL;
+ bool retval = false;
- new_dir = eap->arg;
-#if !defined(UNIX)
- // for non-UNIX ":cd" means: print current directory
- if (*new_dir == NUL) {
- ex_pwd(NULL);
- } else
-#endif
- {
- if (allbuf_locked()) {
- return;
- }
+ if (new_dir == NULL || allbuf_locked()) {
+ return false;
+ }
- // ":cd -": Change to previous directory
- if (STRCMP(new_dir, "-") == 0) {
- if (prev_dir == NULL) {
- EMSG(_("E186: No previous directory"));
- return;
- }
- new_dir = prev_dir;
+ // ":cd -": Change to previous directory
+ if (STRCMP(new_dir, "-") == 0) {
+ pdir = get_prevdir(scope);
+ if (pdir == NULL) {
+ EMSG(_("E186: No previous directory"));
+ return false;
}
+ new_dir = pdir;
+ }
- // Save current directory for next ":cd -"
- tofree = prev_dir;
- if (os_dirname(NameBuff, MAXPATHL) == OK) {
- prev_dir = vim_strsave(NameBuff);
- } else {
- prev_dir = NULL;
- }
+ // Free the previous directory
+ tofree = get_prevdir(scope);
+
+ if (os_dirname(NameBuff, MAXPATHL) == OK) {
+ pdir = vim_strsave(NameBuff);
+ } else {
+ pdir = NULL;
+ }
+
+ switch (scope) {
+ case kCdScopeTabpage:
+ curtab->tp_prevdir = pdir;
+ break;
+ case kCdScopeWindow:
+ curwin->w_prevdir = pdir;
+ break;
+ default:
+ prev_dir = pdir;
+ }
#if defined(UNIX)
- // On Unix ":cd" means: go to home directory.
- if (*new_dir == NUL) {
- // Use NameBuff for home directory name.
- expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
- new_dir = NameBuff;
- }
+ // On Unix ":cd" means: go to home directory.
+ if (*new_dir == NUL) {
+ // Use NameBuff for home directory name.
+ expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
+ new_dir = NameBuff;
+ }
#endif
- CdScope scope = kCdScopeGlobal; // Depends on command invoked
+ 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);
+
+ return retval;
+}
+
+/// ":cd", ":tcd", ":lcd", ":chdir", "tchdir" and ":lchdir".
+void ex_cd(exarg_T *eap)
+{
+ char_u *new_dir;
+ new_dir = eap->arg;
+#if !defined(UNIX) && !defined(VMS)
+ // for non-UNIX ":cd" means: print current directory
+ if (*new_dir == NUL) {
+ ex_pwd(NULL);
+ } else
+#endif
+ {
+ CdScope scope = kCdScopeGlobal;
switch (eap->cmdidx) {
case CMD_tcd:
case CMD_tchdir:
- scope = kCdScopeTab;
+ scope = kCdScopeTabpage;
break;
case CMD_lcd:
case CMD_lchdir:
@@ -7810,18 +7859,12 @@ void ex_cd(exarg_T *eap)
default:
break;
}
-
- if (vim_chdir(new_dir)) {
- EMSG(_(e_failed));
- } else {
- post_chdir(scope, true);
+ if (changedir_func(new_dir, scope)) {
// Echo the new current directory if the command was typed.
if (KeyTyped || p_verbose >= 5) {
ex_pwd(eap);
}
}
-
- xfree(tofree);
}
}
@@ -7834,7 +7877,17 @@ static void ex_pwd(exarg_T *eap)
#ifdef BACKSLASH_IN_FILENAME
slash_adjust(NameBuff);
#endif
- msg(NameBuff);
+ if (p_verbose > 0) {
+ char *context = "global";
+ if (curwin->w_localdir != NULL) {
+ context = "window";
+ } else if (curtab->tp_localdir != NULL) {
+ context = "tabpage";
+ }
+ smsg("[%s] %s", context, (char *)NameBuff);
+ } else {
+ msg(NameBuff);
+ }
} else {
EMSG(_("E187: Unknown"));
}