summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-04-27 20:37:57 +0200
committerBram Moolenaar <Bram@vim.org>2019-04-27 20:37:57 +0200
commit00aa069db8132851a91cfc5ca7f58ef945c75c73 (patch)
tree54e88e9f1c4a981eb265015eabdc2cde2931cc5e /src
parent2155a6abaa5d065ad7b580229321860591126f2e (diff)
patch 8.1.1218: cannot set a directory for a tab pagev8.1.1218
Problem: Cannot set a directory for a tab page. Solution: Add the tab-local directory. (Yegappan Lakshmanan, closes #4212)
Diffstat (limited to 'src')
-rw-r--r--src/eval.c18
-rw-r--r--src/evalfunc.c41
-rw-r--r--src/ex_cmdidxs.h16
-rw-r--r--src/ex_cmds.h6
-rw-r--r--src/ex_docmd.c54
-rw-r--r--src/if_py_both.h2
-rw-r--r--src/proto/eval.pro2
-rw-r--r--src/proto/ex_docmd.pro2
-rw-r--r--src/structs.h3
-rw-r--r--src/testdir/test_getcwd.vim152
-rw-r--r--src/testdir/test_mksession.vim42
-rw-r--r--src/version.c2
-rw-r--r--src/window.c24
13 files changed, 329 insertions, 35 deletions
diff --git a/src/eval.c b/src/eval.c
index a1ad0e673b..0a16900262 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -8704,11 +8704,13 @@ find_win_by_nr_or_id(typval_T *vp)
/*
* Find window specified by "wvp" in tabpage "tvp".
+ * Returns the tab page in 'ptp'
*/
win_T *
find_tabwin(
- typval_T *wvp, /* VAR_UNKNOWN for current window */
- typval_T *tvp) /* VAR_UNKNOWN for current tab page */
+ typval_T *wvp, // VAR_UNKNOWN for current window
+ typval_T *tvp, // VAR_UNKNOWN for current tab page
+ tabpage_T **ptp)
{
win_T *wp = NULL;
tabpage_T *tp = NULL;
@@ -8726,10 +8728,22 @@ find_tabwin(
tp = curtab;
if (tp != NULL)
+ {
wp = find_win_by_nr(wvp, tp);
+ if (wp == NULL && wvp->v_type == VAR_NUMBER
+ && wvp->vval.v_number != -1)
+ // A window with the specified number is not found
+ tp = NULL;
+ }
}
else
+ {
wp = curwin;
+ tp = curtab;
+ }
+
+ if (ptp != NULL)
+ *ptp = tp;
return wp;
}
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 58b8492e56..509a31f0e6 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -1529,7 +1529,7 @@ f_arglistid(typval_T *argvars, typval_T *rettv)
win_T *wp;
rettv->vval.v_number = -1;
- wp = find_tabwin(&argvars[0], &argvars[1]);
+ wp = find_tabwin(&argvars[0], &argvars[1], NULL);
if (wp != NULL)
rettv->vval.v_number = wp->w_alist->id;
}
@@ -5126,25 +5126,44 @@ f_getcompletion(typval_T *argvars, typval_T *rettv)
/*
* "getcwd()" function
+ *
+ * Return the current working directory of a window in a tab page.
+ * First optional argument 'winnr' is the window number or -1 and the second
+ * optional argument 'tabnr' is the tab page number.
+ *
+ * If no arguments are supplied, then return the directory of the current
+ * window.
+ * If only 'winnr' is specified and is not -1 or 0 then return the directory of
+ * the specified window.
+ * If 'winnr' is 0 then return the directory of the current window.
+ * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
+ * directory of the specified tab page. Otherwise return the directory of the
+ * specified window in the specified tab page.
+ * If the window or the tab page doesn't exist then return NULL.
*/
static void
f_getcwd(typval_T *argvars, typval_T *rettv)
{
win_T *wp = NULL;
+ tabpage_T *tp = NULL;
char_u *cwd;
int global = FALSE;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
+ if (argvars[0].v_type == VAR_NUMBER
+ && argvars[0].vval.v_number == -1
+ && argvars[1].v_type == VAR_UNKNOWN)
global = TRUE;
else
- wp = find_tabwin(&argvars[0], &argvars[1]);
+ wp = find_tabwin(&argvars[0], &argvars[1], &tp);
if (wp != NULL && wp->w_localdir != NULL)
rettv->vval.v_string = vim_strsave(wp->w_localdir);
- else if (wp != NULL || global)
+ else if (tp != NULL && tp->tp_localdir != NULL)
+ rettv->vval.v_string = vim_strsave(tp->tp_localdir);
+ else if (wp != NULL || tp != NULL || global)
{
if (globaldir != NULL)
rettv->vval.v_string = vim_strsave(globaldir);
@@ -5333,7 +5352,7 @@ f_getjumplist(typval_T *argvars, typval_T *rettv)
return;
#ifdef FEAT_JUMPLIST
- wp = find_tabwin(&argvars[0], &argvars[1]);
+ wp = find_tabwin(&argvars[0], &argvars[1], NULL);
if (wp == NULL)
return;
@@ -6824,10 +6843,18 @@ f_has_key(typval_T *argvars, typval_T *rettv)
static void
f_haslocaldir(typval_T *argvars, typval_T *rettv)
{
+ tabpage_T *tp = NULL;
win_T *wp = NULL;
- wp = find_tabwin(&argvars[0], &argvars[1]);
- rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
+ wp = find_tabwin(&argvars[0], &argvars[1], &tp);
+
+ // Check for window-local and tab-local directories
+ if (wp != NULL && wp->w_localdir != NULL)
+ rettv->vval.v_number = 1;
+ else if (tp != NULL && tp->tp_localdir != NULL)
+ rettv->vval.v_number = 2;
+ else
+ rettv->vval.v_number = 0;
}
/*
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
index feea5b2bae..1531e68c1b 100644
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -25,12 +25,12 @@ static const unsigned short cmdidxs1[26] =
/* r */ 351,
/* s */ 371,
/* t */ 439,
- /* u */ 482,
- /* v */ 493,
- /* w */ 511,
- /* x */ 525,
- /* y */ 534,
- /* z */ 535
+ /* u */ 484,
+ /* v */ 495,
+ /* w */ 513,
+ /* x */ 527,
+ /* y */ 536,
+ /* z */ 537
};
/*
@@ -60,7 +60,7 @@ static const unsigned char cmdidxs2[26][26] =
/* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 },
/* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 49, 0, 50, 0, 62, 63, 0, 64, 0 },
- /* t */ { 2, 0, 19, 0, 22, 24, 0, 25, 0, 26, 0, 27, 31, 34, 36, 37, 0, 38, 40, 0, 41, 0, 0, 0, 0, 0 },
+ /* t */ { 2, 0, 19, 0, 24, 26, 0, 27, 0, 28, 0, 29, 33, 36, 38, 39, 0, 40, 42, 0, 43, 0, 0, 0, 0, 0 },
/* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* v */ { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 12, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0 },
/* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 12, 13, 0, 0, 0, 0 },
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
-static const int command_count = 548;
+static const int command_count = 550;
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index ac354cda24..27029baf0b 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1479,6 +1479,12 @@ EX(CMD_tabrewind, "tabrewind", ex_tabnext,
EX(CMD_tabs, "tabs", ex_tabs,
TRLBAR|CMDWIN,
ADDR_TABS),
+EX(CMD_tcd, "tcd", ex_cd,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_OTHER),
+EX(CMD_tchdir, "tchdir", ex_cd,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_OTHER),
EX(CMD_tcl, "tcl", ex_tcl,
RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
ADDR_LINES),
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 0086589342..7444697834 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -3692,6 +3692,8 @@ set_one_cmd_context(
break;
case CMD_cd:
case CMD_chdir:
+ case CMD_tcd:
+ case CMD_tchdir:
case CMD_lcd:
case CMD_lchdir:
if (xp->xp_context == EXPAND_FILES)
@@ -7435,13 +7437,17 @@ free_cd_dir(void)
/*
* Deal with the side effects of changing the current directory.
- * When "local" is TRUE then this was after an ":lcd" command.
+ * When "tablocal" is TRUE then this was after an ":tcd" command.
+ * When "winlocal" is TRUE then this was after an ":lcd" command.
*/
void
-post_chdir(int local)
+post_chdir(int tablocal, int winlocal)
{
+ if (!winlocal)
+ // Clear tab local directory for both :cd and :tcd
+ VIM_CLEAR(curtab->tp_localdir);
VIM_CLEAR(curwin->w_localdir);
- if (local)
+ if (winlocal || tablocal)
{
/* If still in global directory, need to remember current
* directory as global directory. */
@@ -7449,7 +7455,12 @@ post_chdir(int local)
globaldir = vim_strsave(prev_dir);
/* Remember this local directory for the window. */
if (mch_dirname(NameBuff, MAXPATHL) == OK)
- curwin->w_localdir = vim_strsave(NameBuff);
+ {
+ if (tablocal)
+ curtab->tp_localdir = vim_strsave(NameBuff);
+ else
+ curwin->w_localdir = vim_strsave(NameBuff);
+ }
}
else
{
@@ -7463,7 +7474,7 @@ post_chdir(int local)
/*
- * ":cd", ":lcd", ":chdir" and ":lchdir".
+ * ":cd", ":tcd", ":lcd", ":chdir" ":tchdir" and ":lchdir".
*/
void
ex_cd(exarg_T *eap)
@@ -7532,19 +7543,29 @@ ex_cd(exarg_T *eap)
emsg(_(e_failed));
else
{
- int is_local_chdir = eap->cmdidx == CMD_lcd
+ 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_local_chdir);
+ post_chdir(is_tablocal_chdir, is_winlocal_chdir);
/* Echo the new current directory if the command was typed. */
if (KeyTyped || p_verbose >= 5)
ex_pwd(eap);
if (dir_differs)
- apply_autocmds(EVENT_DIRCHANGED,
- is_local_chdir ? (char_u *)"window" : (char_u *)"global",
+ {
+ 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);
}
@@ -9729,12 +9750,13 @@ makeopens(
}
for (tabnr = 1; ; ++tabnr)
{
+ tabpage_T *tp = NULL;
int need_tabnext = FALSE;
int cnr = 1;
if ((ssop_flags & SSOP_TABPAGES))
{
- tabpage_T *tp = find_tabpage(tabnr);
+ tp = find_tabpage(tabnr);
if (tp == NULL)
break; /* done all tab pages */
@@ -9833,6 +9855,18 @@ makeopens(
if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
return FAIL;
+ // Restore the tab-local working directory if specified
+ // Do this before the windows, so that the window-local directory can
+ // override the tab-local directory.
+ if (tp != NULL && tp->tp_localdir != NULL && ssop_flags & SSOP_CURDIR)
+ {
+ if (fputs("tcd ", fd) < 0
+ || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ did_lcd = TRUE;
+ }
+
/*
* Restore the view of the window (options, file, cursor, etc.).
*/
diff --git a/src/if_py_both.h b/src/if_py_both.h
index 20affe31db..ede2f5cde4 100644
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -1032,7 +1032,7 @@ _VimChdir(PyObject *_chdir, PyObject *args, PyObject *kwargs)
Py_DECREF(newwd);
Py_XDECREF(todecref);
- post_chdir(FALSE);
+ post_chdir(FALSE, FALSE);
if (VimTryEnd())
{
diff --git a/src/proto/eval.pro b/src/proto/eval.pro
index 0e6182f016..f501300a38 100644
--- a/src/proto/eval.pro
+++ b/src/proto/eval.pro
@@ -116,7 +116,7 @@ void ex_echohl(exarg_T *eap);
void ex_execute(exarg_T *eap);
win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp);
win_T *find_win_by_nr_or_id(typval_T *vp);
-win_T *find_tabwin(typval_T *wvp, typval_T *tvp);
+win_T *find_tabwin(typval_T *wvp, typval_T *tvp, tabpage_T **ptp);
void getwinvar(typval_T *argvars, typval_T *rettv, int off);
void setwinvar(typval_T *argvars, typval_T *rettv, int off);
char_u *autoload_name(char_u *name);
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
index 710f48b781..9934d60fcb 100644
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -37,7 +37,7 @@ void ex_splitview(exarg_T *eap);
void tabpage_new(void);
void do_exedit(exarg_T *eap, win_T *old_curwin);
void free_cd_dir(void);
-void post_chdir(int local);
+void post_chdir(int tablocal, int winlocal);
void ex_cd(exarg_T *eap);
void do_sleep(long msec);
void ex_may_print(exarg_T *eap);
diff --git a/src/structs.h b/src/structs.h
index 89749e5c21..40e87d5500 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -2574,6 +2574,9 @@ struct tabpage_S
int tp_prev_which_scrollbars[3];
/* previous value of which_scrollbars */
#endif
+
+ char_u *tp_localdir; // absolute path of local directory or
+ // NULL
#ifdef FEAT_DIFF
diff_T *tp_first_diff;
buf_T *(tp_diffbuf[DB_COUNT]);
diff --git a/src/testdir/test_getcwd.vim b/src/testdir/test_getcwd.vim
index ca098781e4..50c940febe 100644
--- a/src/testdir/test_getcwd.vim
+++ b/src/testdir/test_getcwd.vim
@@ -97,6 +97,17 @@ function Test_GetCwd()
call assert_equal("y Xdir2 1", GetCwdInfo(2, tp_nr))
call assert_equal("z Xdir3 1", GetCwdInfo(1, tp_nr))
call assert_equal(g:topdir, getcwd(-1))
+ " Non existing windows and tab pages
+ call assert_equal('', getcwd(100))
+ call assert_equal(0, haslocaldir(100))
+ call assert_equal('', getcwd(10, 1))
+ call assert_equal(0, haslocaldir(10, 1))
+ call assert_equal('', getcwd(1, 5))
+ call assert_equal(0, haslocaldir(1, 5))
+ call assert_fails('call getcwd([])', 'E745:')
+ call assert_fails('call getcwd(1, [])', 'E745:')
+ call assert_fails('call haslocaldir([])', 'E745:')
+ call assert_fails('call haslocaldir(1, [])', 'E745:')
endfunc
function Test_GetCwd_lcd_shellslash()
@@ -110,3 +121,144 @@ function Test_GetCwd_lcd_shellslash()
call assert_equal(cwd[-1:], '\')
endif
endfunc
+
+" Test for :tcd
+function Test_Tab_Local_Cwd()
+ enew | only | tabonly
+
+ call mkdir('Xtabdir1')
+ call mkdir('Xtabdir2')
+ call mkdir('Xwindir1')
+ call mkdir('Xwindir2')
+ call mkdir('Xwindir3')
+
+ " Create three tabpages with three windows each
+ edit a
+ botright new b
+ botright new c
+ tabnew m
+ botright new n
+ botright new o
+ tabnew x
+ botright new y
+ botright new z
+
+ " Setup different directories for the tab pages and windows
+ tabrewind
+ 1wincmd w
+ lcd Xwindir1
+ tabnext
+ tcd Xtabdir1
+ 2wincmd w
+ lcd ../Xwindir2
+ tabnext
+ tcd Xtabdir2
+ 3wincmd w
+ lcd ../Xwindir3
+
+ " Check the directories of various windows
+ call assert_equal("a Xwindir1 1", GetCwdInfo(1, 1))
+ call assert_equal("b Xtopdir 0", GetCwdInfo(2, 1))
+ call assert_equal("c Xtopdir 0", GetCwdInfo(3, 1))
+ call assert_equal("m Xtabdir1 2", GetCwdInfo(1, 2))
+ call assert_equal("n Xwindir2 1", GetCwdInfo(2, 2))
+ call assert_equal("o Xtabdir1 2", GetCwdInfo(3, 2))
+ call assert_equal("x Xtabdir2 2", GetCwdInfo(1, 3))
+ call assert_equal("y Xtabdir2 2", GetCwdInfo(2, 3))
+ call assert_equal("z Xwindir3 1", GetCwdInfo(3, 3))
+
+ " Check the tabpage directories
+ call assert_equal('Xtopdir', fnamemodify(getcwd(-1, 1), ':t'))
+ call assert_equal('Xtabdir1', fnamemodify(getcwd(-1, 2), ':t'))
+ call assert_equal('Xtabdir2', fnamemodify(getcwd(-1, 3), ':t'))
+ call assert_equal('', fnamemodify(getcwd(-1, 4), ':t'))
+
+ " Jump to different windows in the tab pages and check the current directory
+ tabrewind | 1wincmd w
+ call assert_equal('Xwindir1', fnamemodify(getcwd(), ':t'))
+ call assert_equal('Xwindir1', fnamemodify(getcwd(0), ':t'))
+ call assert_equal('Xwindir1', fnamemodify(getcwd(0, 0), ':t'))
+ call assert_true(haslocaldir(0))
+ call assert_equal(0, haslocaldir(-1, 0))
+ call assert_equal('Xtopdir', fnamemodify(getcwd(-1, 0), ':t'))
+ call assert_equal(g:topdir, getcwd(-1))
+ 2wincmd w
+ call assert_equal('Xtopdir', fnamemodify(getcwd(), ':t'))
+ call assert_equal('Xtopdir', fnamemodify(getcwd(0), ':t'))
+ call assert_equal('Xtopdir', fnamemodify(getcwd(0, 0), ':t'))
+ call assert_false(haslocaldir(0))
+ call assert_equal(0, haslocaldir(-1, 0))
+ call assert_equal('Xtopdir', fnamemodify(getcwd(-1, 0), ':t'))
+ call assert_equal(g:topdir, getcwd(-1))
+ tabnext | 1wincmd w
+ call assert_equal('Xtabdir1', fnamemodify(getcwd(), ':t'))
+ call assert_equal('Xtabdir1', fnamemodify(getcwd(0), ':t'))
+ call assert_equal('Xtabdir1', fnamemodify(getcwd(0, 0), ':t'))
+ call assert_true(haslocaldir(0))
+ call assert_equal(2, haslocaldir(-1, 0))
+ call assert_equal('Xtabdir1', fnamemodify(getcwd(-1, 0), ':t'))
+ call assert_equal(g:topdir, getcwd(-1))
+ 2wincmd w
+ call assert_equal('Xwindir2', fnamemodify(getcwd(), ':t'))
+ call assert_equal('Xwindir2', fnamemodify(getcwd(0), ':t'))
+ call assert_equal('Xwindir2', fnamemodify(getcwd(0, 0), ':t'))
+ call assert_true(haslocaldir(0))
+ call assert_equal(2, haslocaldir(-1, 0))
+ call assert_equal('Xtabdir1', fnamemodify(getcwd(-1, 0), ':t'))
+ call assert_equal(g:topdir, getcwd(-1))
+ tabnext | 1wincmd w
+ call assert_equal('Xtabdir2', fnamemodify(getcwd(), ':t'))
+ call assert_equal('Xtabdir2', fnamemodify(getcwd(0), ':t'))
+ call assert_equal('Xtabdir2', fnamemodify(getcwd(0, 0), ':t'))
+ call assert_true(haslocaldir(0))
+ call assert_equal(2, haslocaldir(-1, 0))
+ call assert_equal('Xtabdir2', fnamemodify(getcwd(-1, 0), ':t'))
+ call assert_equal(g:topdir, getcwd(-1))
+ 3wincmd w
+ call assert_equal('Xwindir3', fnamemodify(getcwd(), ':t'))
+ call assert_equal('Xwindir3', fnamemodify(getcwd(0), ':t'))
+ call assert_equal('Xwindir3', fnamemodify(getcwd(0, 0), ':t'))
+ call assert_true(haslocaldir(0))
+ call assert_equal(2, haslocaldir(-1, 0))
+ call assert_equal('Xtabdir2', fnamemodify(getcwd(-1, 0), ':t'))
+ call assert_equal(g:topdir, getcwd(-1))
+
+ " A new tab page should inherit the directory of the current tab page
+ tabrewind | 1wincmd w
+ tabnew g
+ call assert_equal("g Xwindir1 1", GetCwdInfo(0, 0))
+ tabclose | tabrewind
+ 2wincmd w
+ tabnew h
+ call assert_equal("h Xtopdir 0", GetCwdInfo(0, 0))
+ tabclose
+ tabnext 2 | 1wincmd w
+ tabnew j
+ call assert_equal("j Xtabdir1 2", GetCwdInfo(0, 0))
+ tabclose
+
+ " Change the global directory for the first tab page
+ tabrewind | 1wincmd w
+ cd ../Xdir1
+ call assert_equal("a Xdir1 0", GetCwdInfo(1, 1))
+ call assert_equal("b Xdir1 0", GetCwdInfo(2, 1))
+ call assert_equal("m Xtabdir1 2", GetCwdInfo(1, 2))
+ call assert_equal("n Xwindir2 1", GetCwdInfo(2, 2))
+
+ " Change the global directory for the second tab page
+ tabnext | 1wincmd w
+ cd ../Xdir3
+ call assert_equal("m Xdir3 0", GetCwdInfo(1, 2))
+ call assert_equal("n Xwindir2 1", GetCwdInfo(2, 2))
+ call assert_equal("o Xdir3 0", GetCwdInfo(3, 2))
+
+ " Change the tab-local directory for the third tab page
+ tabnext | 1wincmd w
+ cd ../Xdir1
+ call assert_equal("x Xdir1 0", GetCwdInfo(1, 3))
+ call assert_equal("y Xdir1 0", GetCwdInfo(2, 3))
+ call assert_equal("z Xwindir3 1", GetCwdInfo(3, 3))
+
+ enew | only | tabonly
+ new
+endfunc
diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim
index 456cd1e423..bc413968b4 100644
--- a/src/testdir/test_mksession.vim
+++ b/src/testdir/test_mksession.vim
@@ -210,6 +210,48 @@ func Test_mksession_lcd_multiple_tabs()
call delete('Xtest_mks.out')
endfunc
+" Test for tabpage-local directory
+func Test_mksession_tcd_multiple_tabs()
+ let save_cwd = getcwd()
+ call mkdir('Xtopdir')
+ cd Xtopdir
+ call mkdir('Xtabdir1')
+ call mkdir('Xtabdir2')
+ call mkdir('Xtabdir3')
+ call mkdir('Xwindir1')
+ call mkdir('Xwindir2')
+ call mkdir('Xwindir3')
+ tcd Xtabdir1
+ botright new
+ wincmd t
+ lcd ../Xwindir1
+ tabnew
+ tcd ../Xtabdir2
+ botright new
+ lcd ../Xwindir2
+ tabnew
+ tcd ../Xtabdir3
+ botright new
+ lcd ../Xwindir3
+ tabfirst
+ 1wincmd w
+ mksession! Xtest_mks.out
+ only | tabonly
+ source Xtest_mks.out
+ call assert_equal('Xtabdir1', fnamemodify(getcwd(-1, 1), ':t'))
+ call assert_equal('Xwindir1', fnamemodify(getcwd(1, 1), ':t'))
+ call assert_equal('Xtabdir1', fnamemodify(getcwd(2, 1), ':t'))
+ call assert_equal('Xtabdir2', fnamemodify(getcwd(-1, 2), ':t'))
+ call assert_equal('Xtabdir2', fnamemodify(getcwd(1, 2), ':t'))
+ call assert_equal('Xwindir2', fnamemodify(getcwd(2, 2), ':t'))
+ call assert_equal('Xtabdir3', fnamemodify(getcwd(-1, 3), ':t'))
+ call assert_equal('Xtabdir3', fnamemodify(getcwd(1, 3), ':t'))
+ call assert_equal('Xwindir3', fnamemodify(getcwd(2, 3), ':t'))
+ only | tabonly
+ exe 'cd ' . save_cwd
+ call delete("Xtopdir", "rf")
+endfunc
+
func Test_mksession_blank_tabs()
tabnew
tabnew
diff --git a/src/version.c b/src/version.c
index 4c2620f291..25884c3768 100644
--- a/src/version.c
+++ b/src/version.c
@@ -768,6 +768,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1218,
+/**/
1217,
/**/
1216,
diff --git a/src/window.c b/src/window.c
index b132361a5a..4a92d6cb50 100644
--- a/src/window.c
+++ b/src/window.c
@@ -3625,6 +3625,8 @@ free_tabpage(tabpage_T *tp)
unref_var_dict(tp->tp_vars);
#endif
+ vim_free(tp->tp_localdir);
+
#ifdef FEAT_PYTHON
python_tabpage_free(tp);
#endif
@@ -3662,6 +3664,8 @@ win_new_tabpage(int after)
}
curtab = newtp;
+ newtp->tp_localdir = (tp->tp_localdir == NULL)
+ ? NULL : vim_strsave(tp->tp_localdir);
/* Create a new empty window. */
if (win_alloc_firstwin(tp->tp_curwin) == OK)
{
@@ -3839,6 +3843,9 @@ find_tabpage(int n)
tabpage_T *tp;
int i = 1;
+ if (n == 0)
+ return curtab;
+
for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next)
++i;
return tp;
@@ -4451,11 +4458,13 @@ win_enter_ext(
curwin->w_cursor.coladd = 0;
changed_line_abv_curs(); /* assume cursor position needs updating */
- if (curwin->w_localdir != NULL)
+ if (curwin->w_localdir != NULL || curtab->tp_localdir != NULL)
{
- /* Window has a local directory: Save current directory as global
- * directory (unless that was done already) and change to the local
- * directory. */
+ char_u *dirname;
+
+ // Window or tab has a local directory: Save current directory as
+ // global directory (unless that was done already) and change to the
+ // local directory.
if (globaldir == NULL)
{
char_u cwd[MAXPATHL];
@@ -4463,7 +4472,12 @@ win_enter_ext(
if (mch_dirname(cwd, MAXPATHL) == OK)
globaldir = vim_strsave(cwd);
}
- if (mch_chdir((char *)curwin->w_localdir) == 0)
+ if (curwin->w_localdir != NULL)
+ dirname = curwin->w_localdir;
+ else
+ dirname = curtab->tp_localdir;
+
+ if (mch_chdir((char *)dirname) == 0)
shorten_fnames(TRUE);
}
else if (globaldir != NULL)