diff src/ex_docmd.c @ 16576:bcc343175103 v8.1.1291

patch 8.1.1291: not easy to change directory and restore commit https://github.com/vim/vim/commit/1063f3d2008f22d02ccfa9dab83a23db52febbdc Author: Bram Moolenaar <Bram@vim.org> Date: Tue May 7 22:06:52 2019 +0200 patch 8.1.1291: not easy to change directory and restore Problem: Not easy to change directory and restore. Solution: Add the chdir() function. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/4358)
author Bram Moolenaar <Bram@vim.org>
date Tue, 07 May 2019 22:15:05 +0200
parents 6e87a69b8e0c
children 0422b14bce58
line wrap: on
line diff
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -7513,17 +7513,17 @@ free_cd_dir(void)
 
 /*
  * Deal with the side effects of changing the current directory.
- * When "tablocal" is TRUE then this was after an ":tcd" command.
- * When "winlocal" is TRUE then this was after an ":lcd" command.
+ * When 'scope' is CDSCOPE_TABPAGE then this was after an ":tcd" command.
+ * When 'scope' is CDSCOPE_WINDOW then this was after an ":lcd" command.
  */
     void
-post_chdir(int tablocal, int winlocal)
-{
-    if (!winlocal)
+post_chdir(cdscope_T scope)
+{
+    if (scope != CDSCOPE_WINDOW)
 	// Clear tab local directory for both :cd and :tcd
 	VIM_CLEAR(curtab->tp_localdir);
     VIM_CLEAR(curwin->w_localdir);
-    if (winlocal || tablocal)
+    if (scope != CDSCOPE_GLOBAL)
     {
 	/* If still in global directory, need to remember current
 	 * directory as global directory. */
@@ -7532,7 +7532,7 @@ post_chdir(int tablocal, int winlocal)
 	/* Remember this local directory for the window. */
 	if (mch_dirname(NameBuff, MAXPATHL) == OK)
 	{
-	    if (tablocal)
+	    if (scope == CDSCOPE_TABPAGE)
 		curtab->tp_localdir = vim_strsave(NameBuff);
 	    else
 		curwin->w_localdir = vim_strsave(NameBuff);
@@ -7548,6 +7548,96 @@ post_chdir(int tablocal, int winlocal)
     shorten_fnames(TRUE);
 }
 
+/*
+ * Change directory function used by :cd/:tcd/:lcd Ex commands and the
+ * chdir() function. If 'winlocaldir' is TRUE, then changes the window-local
+ * directory. If 'tablocaldir' is TRUE, then changes the tab-local directory.
+ * Otherwise changes the global directory.
+ * Returns TRUE if the directory is successfully changed.
+ */
+    int
+changedir_func(
+	char_u		*new_dir,
+	int		forceit,
+	cdscope_T	scope)
+{
+    char_u	*tofree;
+    int		dir_differs;
+    int		retval = FALSE;
+
+    if (allbuf_locked())
+	return FALSE;
+
+    if (vim_strchr(p_cpo, CPO_CHDIR) != NULL && curbufIsChanged() && !forceit)
+    {
+	emsg(_("E747: Cannot change directory, buffer is modified (add ! to override)"));
+	return FALSE;
+    }
+
+    // ":cd -": Change to previous directory
+    if (STRCMP(new_dir, "-") == 0)
+    {
+	if (prev_dir == NULL)
+	{
+	    emsg(_("E186: No previous directory"));
+	    return FALSE;
+	}
+	new_dir = prev_dir;
+    }
+
+    // Save current directory for next ":cd -"
+    tofree = prev_dir;
+    if (mch_dirname(NameBuff, MAXPATHL) == OK)
+	prev_dir = vim_strsave(NameBuff);
+    else
+	prev_dir = NULL;
+
+#if defined(UNIX) || defined(VMS)
+    // for UNIX ":cd" means: go to home directory
+    if (*new_dir == NUL)
+    {
+	// use NameBuff for home directory name
+# ifdef VMS
+	char_u	*p;
+
+	p = mch_getenv((char_u *)"SYS$LOGIN");
+	if (p == NULL || *p == NUL)	// empty is the same as not set
+	    NameBuff[0] = NUL;
+	else
+	    vim_strncpy(NameBuff, p, MAXPATHL - 1);
+# else
+	expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
+# endif
+	new_dir = NameBuff;
+    }
+#endif
+    dir_differs = new_dir == NULL || prev_dir == NULL
+	|| pathcmp((char *)prev_dir, (char *)new_dir, -1) != 0;
+    if (new_dir == NULL || (dir_differs && vim_chdir(new_dir)))
+	emsg(_(e_failed));
+    else
+    {
+	char_u  *acmd_fname;
+
+	post_chdir(scope);
+
+	if (dir_differs)
+	{
+	    if (scope == CDSCOPE_WINDOW)
+		acmd_fname = (char_u *)"window";
+	    else if (scope == CDSCOPE_TABPAGE)
+		acmd_fname = (char_u *)"tabpage";
+	    else
+		acmd_fname = (char_u *)"global";
+	    apply_autocmds(EVENT_DIRCHANGED, acmd_fname, new_dir, FALSE,
+								curbuf);
+	}
+	retval = TRUE;
+    }
+    vim_free(tofree);
+
+    return retval;
+}
 
 /*
  * ":cd", ":tcd", ":lcd", ":chdir" ":tchdir" and ":lchdir".
@@ -7556,94 +7646,28 @@ post_chdir(int tablocal, int winlocal)
 ex_cd(exarg_T *eap)
 {
     char_u	*new_dir;
-    char_u	*tofree;
-    int		dir_differs;
 
     new_dir = eap->arg;
 #if !defined(UNIX) && !defined(VMS)
-    /* for non-UNIX ":cd" means: print current directory */
+    // for non-UNIX ":cd" means: print current directory
     if (*new_dir == NUL)
 	ex_pwd(NULL);
     else
 #endif
     {
-	if (allbuf_locked())
-	    return;
-	if (vim_strchr(p_cpo, CPO_CHDIR) != NULL && curbufIsChanged()
-							     && !eap->forceit)
-	{
-	    emsg(_("E747: Cannot change directory, buffer is modified (add ! to override)"));
-	    return;
-	}
-
-	/* ":cd -": Change to previous directory */
-	if (STRCMP(new_dir, "-") == 0)
-	{
-	    if (prev_dir == NULL)
-	    {
-		emsg(_("E186: No previous directory"));
-		return;
-	    }
-	    new_dir = prev_dir;
-	}
-
-	/* Save current directory for next ":cd -" */
-	tofree = prev_dir;
-	if (mch_dirname(NameBuff, MAXPATHL) == OK)
-	    prev_dir = vim_strsave(NameBuff);
-	else
-	    prev_dir = NULL;
-
-#if defined(UNIX) || defined(VMS)
-	/* for UNIX ":cd" means: go to home directory */
-	if (*new_dir == NUL)
-	{
-	    /* use NameBuff for home directory name */
-# ifdef VMS
-	    char_u	*p;
-
-	    p = mch_getenv((char_u *)"SYS$LOGIN");
-	    if (p == NULL || *p == NUL)	/* empty is the same as not set */
-		NameBuff[0] = NUL;
-	    else
-		vim_strncpy(NameBuff, p, MAXPATHL - 1);
-# else
-	    expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
-# endif
-	    new_dir = NameBuff;
-	}
-#endif
-	dir_differs = new_dir == NULL || prev_dir == NULL
-			|| pathcmp((char *)prev_dir, (char *)new_dir, -1) != 0;
-	if (new_dir == NULL || (dir_differs && vim_chdir(new_dir)))
-	    emsg(_(e_failed));
-	else
-	{
-	    char_u  *acmd_fname;
-	    int is_winlocal_chdir = eap->cmdidx == CMD_lcd
-						  || eap->cmdidx == CMD_lchdir;
-	    int is_tablocal_chdir = eap->cmdidx == CMD_tcd
-						  || eap->cmdidx == CMD_tchdir;
-
-	    post_chdir(is_tablocal_chdir, is_winlocal_chdir);
-
-	    /* Echo the new current directory if the command was typed. */
+	cdscope_T	scope = CDSCOPE_GLOBAL;
+
+	if (eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir)
+	    scope = CDSCOPE_WINDOW;
+	else if (eap->cmdidx == CMD_tcd || eap->cmdidx == CMD_tchdir)
+	    scope = CDSCOPE_TABPAGE;
+
+	if (changedir_func(new_dir, eap->forceit, scope))
+	{
+	    // Echo the new current directory if the command was typed.
 	    if (KeyTyped || p_verbose >= 5)
 		ex_pwd(eap);
-
-	    if (dir_differs)
-	    {
-		if (is_winlocal_chdir)
-		    acmd_fname = (char_u *)"window";
-		else if (is_tablocal_chdir)
-		    acmd_fname = (char_u *)"tabpage";
-		else
-		    acmd_fname = (char_u *)"global";
-		apply_autocmds(EVENT_DIRCHANGED, acmd_fname,
-		      new_dir, FALSE, curbuf);
-	    }
-	}
-	vim_free(tofree);
+	}
     }
 }