Patch 8.1.1218
Problem: Cannot set a directory for a tab page.
Solution: Add the tab-local directory. (Yegappan Lakshmanan, closes #4212)
Files: runtime/doc/autocmd.txt, runtime/doc/editing.txt,
runtime/doc/eval.txt, runtime/doc/index.txt,
runtime/doc/options.txt, runtime/doc/usr_22.txt,
runtime/doc/usr_41.txt, src/eval.c, src/evalfunc.c,
src/ex_cmdidxs.h, src/ex_cmds.h, src/ex_docmd.c, src/if_py_both.h,
src/proto/eval.pro, src/proto/ex_docmd.pro, src/structs.h,
src/testdir/test_getcwd.vim, src/testdir/test_mksession.vim,
src/window.c
*** ../vim-8.1.1217/runtime/doc/autocmd.txt 2019-04-08 18:15:36.464223229
+0200
--- runtime/doc/autocmd.txt 2019-04-27 20:06:26.758264881 +0200
***************
*** 686,704 ****
change or when doing |:diffupdate|.
*DirChanged*
DirChanged The working directory has changed in response
! to the |:cd| or |:lcd| commands, or as a
! result of the 'autochdir' option.
The pattern can be:
! "window" to trigger on `:lcd`
! "global" to trigger on `:cd`
! "auto" to trigger on 'autochdir'.
! "drop" to trigger on editing a file
<afile> is set to the new directory name.
*ExitPre*
ExitPre When using `:quit`, `:wq` in a way it
makes
Vim exit, or using `:qall`, just after
|QuitPre|. Can be used to close any
! non-essential window.
*FileChangedShell*
FileChangedShell When Vim notices that the modification time of
a file has changed since editing started.
--- 690,712 ----
change or when doing |:diffupdate|.
*DirChanged*
DirChanged The working directory has changed in response
! to the |:cd| or |:tcd| or |:lcd| commands, or
! as a result of the 'autochdir' option.
The pattern can be:
! "window" to trigger on `:lcd`
! "tabpage" to trigger on `:tcd`
! "global" to trigger on `:cd`
! "auto" to trigger on 'autochdir'.
! "drop" to trigger on editing a file
<afile> is set to the new directory name.
*ExitPre*
ExitPre When using `:quit`, `:wq` in a way it
makes
Vim exit, or using `:qall`, just after
|QuitPre|. Can be used to close any
! non-essential window. Exiting may still be
! cancelled if there is a modified buffer that
! isn't automatically saved, use |VimLeavePre|
! for really exiting.
*FileChangedShell*
FileChangedShell When Vim notices that the modification time of
a file has changed since editing started.
*** ../vim-8.1.1217/runtime/doc/editing.txt 2018-05-17 13:40:51.000000000
+0200
--- runtime/doc/editing.txt 2019-04-27 20:11:37.192857657 +0200
***************
*** 1304,1312 ****
==============================================================================
7. The current directory *current-directory*
! You may use the |:cd| and |:lcd| commands to change to another directory, so
! you will not have to type that directory name in front of the file names. It
! also makes a difference for executing external commands, e.g. ":!ls".
Changing directory fails when the current buffer is modified, the '.' flag is
present in 'cpoptions' and "!" is not used in the command.
--- 1304,1313 ----
==============================================================================
7. The current directory *current-directory*
! You can use the |:cd|, |:tcd| and |:lcd| commands to change to another
! directory, so you will not have to type that directory name in front of the
! file names. It also makes a difference for executing external commands, e.g.
! ":!ls".
Changing directory fails when the current buffer is modified, the '.' flag is
present in 'cpoptions' and "!" is not used in the command.
***************
*** 1334,1339 ****
--- 1335,1351 ----
*:chd* *:chdir*
:chd[ir][!] [path] Same as |:cd|.
+ *:tcd*
+ :tcd[!] {path} Like |:cd|, but only set the directory for the
current
+ tab. The current window will also use this directory.
+ The current directory is not changed for windows in
+ other tabs and for windows in the current tab that
+ have their own window-local directory.
+ {not in Vi}
+
+ *:tch* *:tchdir*
+ :tch[dir][!] Same as |:tcd|. {not in Vi}
+
*:lc* *:lcd*
:lc[d][!] {path} Like |:cd|, but only set the current directory when
the cursor is in the current window. The current
***************
*** 1348,1364 ****
:pw[d] Print the current directory name. {Vi: no pwd}
Also see |getcwd()|.
! So long as no |:lcd| command has been used, all windows share the same current
! directory. Using a command to jump to another window doesn't change anything
! for the current directory.
When a |:lcd| command has been used for a window, the specified directory
becomes the current directory for that window. Windows where the |:lcd|
! command has not been used stick to the global current directory. When jumping
! to another window the current directory will become the last specified local
! current directory. If none was specified, the global current directory is
! used.
! When a |:cd| command is used, the current window will lose his local current
! directory and will use the global current directory from now on.
After using |:cd| the full path name will be used for reading and writing
files. On some networked file systems this may cause problems. The result of
--- 1360,1385 ----
:pw[d] Print the current directory name. {Vi: no pwd}
Also see |getcwd()|.
! So long as no |:lcd| or |:tcd| command has been used, all windows share the
! same current directory. Using a command to jump to another window doesn't
! change anything for the current directory.
!
When a |:lcd| command has been used for a window, the specified directory
becomes the current directory for that window. Windows where the |:lcd|
! command has not been used stick to the global or tab-local current directory.
! When jumping to another window the current directory will become the last
! specified local current directory. If none was specified, the global or
! tab-local current directory is used.
!
! When a |:tcd| command has been used for a tab page, the specified directory
! becomes the current directory for the current tab page and the current window.
! The current directory of other tab pages is not affected. When jumping to
! another tab page, the current directory will become the last specified local
! directory for that tab page. If the current tab has no local current directory
! the global current directory is used.
!
! When a |:cd| command is used, the current window and tab page will lose the
! local current directory and will use the global current directory from now on.
After using |:cd| the full path name will be used for reading and writing
files. On some networked file systems this may cause problems. The result of
*** ../vim-8.1.1217/runtime/doc/eval.txt 2019-04-27 13:03:20.012715914
+0200
--- runtime/doc/eval.txt 2019-04-27 20:14:41.136007351 +0200
***************
*** 2377,2382 ****
--- 2398,2404 ----
has_key({dict}, {key}) Number |TRUE| if {dict} has entry {key}
haslocaldir([{winnr} [, {tabnr}]])
Number |TRUE| if the window executed |:lcd|
+ or |:tcd|
hasmapto({what} [, {mode} [, {abbr}]])
Number |TRUE| if mapping to {what} exists
histadd({history}, {item}) String add an item to a history
***************
*** 4880,4886 ****
getcwd([{winnr} [, {tabnr}]])
The result is a String, which is the name of the current
working directory.
- Without arguments, for the current window.
With {winnr} return the local current directory of this window
in the current tab page. {winnr} can be the window number or
--- 4911,4916 ----
***************
*** 4889,4897 ****
directory. See also |haslocaldir()|.
With {winnr} and {tabnr} return the local current directory of
! the window in the specified tab page.
Return an empty string if the arguments are invalid.
getfsize({fname}) *getfsize()*
The result is a Number, which is the size in bytes of the
given file {fname}.
--- 4919,4946 ----
directory. See also |haslocaldir()|.
With {winnr} and {tabnr} return the local current directory of
! the window in the specified tab page. If {winnr} is -1 return
! the working directory of the tabpage.
! If {winnr} is zero use the current window, if {tabnr} is zero
! use the current tabpage.
! Without any arguments, return the working directory of the
! current window.
Return an empty string if the arguments are invalid.
+ Examples: >
+ " Get the working directory of the current window
+ :echo getcwd()
+ :echo getcwd(0)
+ :echo getcwd(0, 0)
+ " Get the working directory of window 3 in tabpage 2
+ :echo getcwd(3, 2)
+ " Get the global working directory
+ :echo getcwd(-1)
+ " Get the working directory of tabpage 3
+ :echo getcwd(-1, 3)
+ " Get the working directory of current tabpage
+ :echo getcwd(-1, 0)
+ <
getfsize({fname}) *getfsize()*
The result is a Number, which is the size in bytes of the
given file {fname}.
***************
*** 5449,5464 ****
an entry with key {key}. Zero otherwise.
haslocaldir([{winnr} [, {tabnr}]]) *haslocaldir()*
! The result is a Number, which is 1 when the window has set a
! local path via |:lcd|, and 0 otherwise.
Without arguments use the current window.
With {winnr} use this window in the current tab page.
With {winnr} and {tabnr} use the window in the specified tab
page.
{winnr} can be the window number or the |window-ID|.
Return 0 if the arguments are invalid.
hasmapto({what} [, {mode} [, {abbr}]]) *hasmapto()*
The result is a Number, which is 1 if there is a mapping that
contains {what} in somewhere in the rhs (what it is mapped to)
--- 5498,5536 ----
an entry with key {key}. Zero otherwise.
haslocaldir([{winnr} [, {tabnr}]]) *haslocaldir()*
! The result is a Number:
! 1 when the window has set a local directory via |:lcd|
! 2 when the tab-page has set a local directory via |:tcd|
! 0 otherwise.
Without arguments use the current window.
With {winnr} use this window in the current tab page.
With {winnr} and {tabnr} use the window in the specified tab
page.
{winnr} can be the window number or the |window-ID|.
+ If {winnr} is -1 it is ignored and only the tabpage is used.
Return 0 if the arguments are invalid.
+ Examples: >
+ if haslocaldir() == 1
+ " window local directory case
+ elseif haslocaldir() == 2
+ " tab-local directory case
+ else
+ " global directory case
+ endif
+ " current window
+ :echo haslocaldir()
+ :echo haslocaldir(0)
+ :echo haslocaldir(0, 0)
+ " window n in current tab page
+ :echo haslocaldir(n)
+ :echo haslocaldir(n, 0)
+ " window n in tab page m
+ :echo haslocaldir(n, m)
+ " tab page m
+ :echo haslocaldir(-1, m)
+ <
hasmapto({what} [, {mode} [, {abbr}]]) *hasmapto()*
The result is a Number, which is 1 if there is a mapping that
contains {what} in somewhere in the rhs (what it is mapped to)
*** ../vim-8.1.1217/runtime/doc/index.txt 2018-10-19 22:35:04.885189994
+0200
--- runtime/doc/index.txt 2019-04-27 20:05:21.278555302 +0200
***************
*** 1573,1578 ****
--- 1627,1634 ----
|:tab| :tab create new tab when opening new window
|:tag| :ta[g] jump to tag
|:tags| :tags show the contents of the tag stack
+ |:tcd| :tcd change directory for tab page
+ |:tchdir| :tch[dir] change directory for tab page
|:tcl| :tc[l] execute Tcl command
|:tcldo| :tcld[o] execute Tcl command for each line
|:tclfile| :tclf[ile] execute Tcl script file
*** ../vim-8.1.1217/runtime/doc/options.txt 2019-02-16 15:09:21.225946157
+0100
--- runtime/doc/options.txt 2019-04-27 20:05:21.278555302 +0200
***************
*** 1457,1465 ****
{not available when compiled without the
|+file_in_path| feature}
This is a list of directories which will be searched when using the
! |:cd| and |:lcd| commands, provided that the directory being searched
! for has a relative path, not an absolute part starting with "/", "./"
! or "../", the 'cdpath' option is not used then.
The 'cdpath' option's value has the same form and semantics as
|'path'|. Also see |file-searching|.
The default value is taken from $CDPATH, with a "," prepended to look
--- 1455,1463 ----
{not available when compiled without the
|+file_in_path| feature}
This is a list of directories which will be searched when using the
! |:cd|, |:tcd| and |:lcd| commands, provided that the directory being
! searched for has a relative path, not an absolute part starting with
! "/", "./" or "../", the 'cdpath' option is not used then.
The 'cdpath' option's value has the same form and semantics as
|'path'|. Also see |file-searching|.
The default value is taken from $CDPATH, with a "," prepended to look
*** ../vim-8.1.1217/runtime/doc/usr_22.txt 2018-05-17 13:42:03.000000000
+0200
--- runtime/doc/usr_22.txt 2019-04-27 20:17:02.375349029 +0200
***************
*** 202,215 ****
:pwd
/home/Bram/VeryLongFileName
! So long as no ":lcd" command has been used, all windows share the same current
! directory. Doing a ":cd" command in one window will also change the current
directory of the other window.
! For a window where ":lcd" has been used a different current directory is
! remembered. Using ":cd" or ":lcd" in other windows will not change it.
! When using a ":cd" command in a window that uses a different current
directory, it will go back to using the shared directory.
==============================================================================
*22.3* Finding a file
--- 202,229 ----
:pwd
/home/Bram/VeryLongFileName
! So long as no `:lcd` command has been used, all windows share the same current
! directory. Doing a `:cd` command in one window will also change the current
directory of the other window.
! For a window where `:lcd` has been used a different current directory is
! remembered. Using `:cd` or `:lcd` in other windows will not change it.
! When using a `:cd` command in a window that uses a different current
directory, it will go back to using the shared directory.
+
+ TAB LOCAL DIRECTORY
+
+ When you open a new tab page, it uses the directory of the window in the
+ previous tab page from which the new tab page was opened. You can change the
+ directory of the current tab page using the `:tcd` command. All the windows in
+ a tab page share this directory except for windows with a window-local
+ directory. Any new windows opened in this tab page will use this directory as
+ the current working directory. Using a `:cd` command in a tab page will not
+ change the working directory of tab pages which have a tab local directory.
+ When the global working directory is changed using the ":cd" command in a tab
+ page, it will also change the current tab page working directory.
+
+
==============================================================================
*22.3* Finding a file
*** ../vim-8.1.1217/runtime/doc/usr_41.txt 2019-04-06 13:18:06.733335092
+0200
--- runtime/doc/usr_41.txt 2019-04-27 20:05:21.278555302 +0200
***************
*** 765,771 ****
isdirectory() check if a directory exists
getfsize() get the size of a file
getcwd() get the current working directory
! haslocaldir() check if current window used |:lcd|
tempname() get the name of a temporary file
mkdir() create a new directory
delete() delete a file
--- 766,772 ----
isdirectory() check if a directory exists
getfsize() get the size of a file
getcwd() get the current working directory
! haslocaldir() check if current window used |:lcd| or |:tcd|
tempname() get the name of a temporary file
mkdir() create a new directory
delete() delete a file
*** ../vim-8.1.1217/src/eval.c 2019-04-27 13:03:20.004715961 +0200
--- src/eval.c 2019-04-27 20:17:32.523208020 +0200
***************
*** 8704,8714 ****
/*
* Find window specified by "wvp" in tabpage "tvp".
*/
win_T *
find_tabwin(
! typval_T *wvp, /* VAR_UNKNOWN for current window */
! typval_T *tvp) /* VAR_UNKNOWN for current tab page */
{
win_T *wp = NULL;
tabpage_T *tp = NULL;
--- 8704,8716 ----
/*
* 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
! tabpage_T **ptp)
{
win_T *wp = NULL;
tabpage_T *tp = NULL;
***************
*** 8726,8735 ****
--- 8728,8749 ----
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;
}
*** ../vim-8.1.1217/src/evalfunc.c 2019-04-27 13:03:20.004715961 +0200
--- src/evalfunc.c 2019-04-27 20:05:21.282555283 +0200
***************
*** 1529,1535 ****
win_T *wp;
rettv->vval.v_number = -1;
! wp = find_tabwin(&argvars[0], &argvars[1]);
if (wp != NULL)
rettv->vval.v_number = wp->w_alist->id;
}
--- 1529,1535 ----
win_T *wp;
rettv->vval.v_number = -1;
! wp = find_tabwin(&argvars[0], &argvars[1], NULL);
if (wp != NULL)
rettv->vval.v_number = wp->w_alist->id;
}
***************
*** 5126,5150 ****
/*
* "getcwd()" function
*/
static void
f_getcwd(typval_T *argvars, typval_T *rettv)
{
win_T *wp = 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)
global = TRUE;
else
! wp = find_tabwin(&argvars[0], &argvars[1]);
if (wp != NULL && wp->w_localdir != NULL)
rettv->vval.v_string = vim_strsave(wp->w_localdir);
! else if (wp != NULL || global)
{
if (globaldir != NULL)
rettv->vval.v_string = vim_strsave(globaldir);
--- 5126,5169 ----
/*
* "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
! && argvars[1].v_type == VAR_UNKNOWN)
global = TRUE;
else
! 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 (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,5339 ****
return;
#ifdef FEAT_JUMPLIST
! wp = find_tabwin(&argvars[0], &argvars[1]);
if (wp == NULL)
return;
--- 5352,5358 ----
return;
#ifdef FEAT_JUMPLIST
! wp = find_tabwin(&argvars[0], &argvars[1], NULL);
if (wp == NULL)
return;
***************
*** 6824,6833 ****
static void
f_haslocaldir(typval_T *argvars, typval_T *rettv)
{
win_T *wp = NULL;
! wp = find_tabwin(&argvars[0], &argvars[1]);
! rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
}
/*
--- 6843,6860 ----
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], &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;
}
/*
*** ../vim-8.1.1217/src/ex_cmdidxs.h 2019-04-04 18:15:05.770857065 +0200
--- src/ex_cmdidxs.h 2019-04-27 20:05:21.282555283 +0200
***************
*** 25,36 ****
/* r */ 351,
/* s */ 371,
/* t */ 439,
! /* u */ 482,
! /* v */ 493,
! /* w */ 511,
! /* x */ 525,
! /* y */ 534,
! /* z */ 535
};
/*
--- 25,36 ----
/* r */ 351,
/* s */ 371,
/* t */ 439,
! /* u */ 484,
! /* v */ 495,
! /* w */ 513,
! /* x */ 527,
! /* y */ 536,
! /* z */ 537
};
/*
***************
*** 60,66 ****
/* 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 },
/* 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 },
--- 60,66 ----
/* 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, 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,72 ****
/* 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;
--- 69,72 ----
/* 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 = 550;
*** ../vim-8.1.1217/src/ex_cmds.h 2019-04-27 13:03:20.004715961 +0200
--- src/ex_cmds.h 2019-04-27 20:18:38.294899911 +0200
***************
*** 1479,1484 ****
--- 1479,1490 ----
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),
*** ../vim-8.1.1217/src/ex_docmd.c 2019-04-27 13:03:20.004715961 +0200
--- src/ex_docmd.c 2019-04-27 20:05:21.282555283 +0200
***************
*** 3692,3697 ****
--- 3692,3699 ----
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,7447 ****
/*
* Deal with the side effects of changing the current directory.
! * When "local" is TRUE then this was after an ":lcd" command.
*/
void
! post_chdir(int local)
{
VIM_CLEAR(curwin->w_localdir);
! if (local)
{
/* If still in global directory, need to remember current
* directory as global directory. */
--- 7437,7453 ----
/*
* 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.
*/
void
! 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 (winlocal || tablocal)
{
/* If still in global directory, need to remember current
* directory as global directory. */
***************
*** 7449,7455 ****
globaldir = vim_strsave(prev_dir);
/* Remember this local directory for the window. */
if (mch_dirname(NameBuff, MAXPATHL) == OK)
! curwin->w_localdir = vim_strsave(NameBuff);
}
else
{
--- 7455,7466 ----
globaldir = vim_strsave(prev_dir);
/* Remember this local directory for the window. */
if (mch_dirname(NameBuff, MAXPATHL) == OK)
! {
! if (tablocal)
! curtab->tp_localdir = vim_strsave(NameBuff);
! else
! curwin->w_localdir = vim_strsave(NameBuff);
! }
}
else
{
***************
*** 7463,7469 ****
/*
! * ":cd", ":lcd", ":chdir" and ":lchdir".
*/
void
ex_cd(exarg_T *eap)
--- 7474,7480 ----
/*
! * ":cd", ":tcd", ":lcd", ":chdir" ":tchdir" and ":lchdir".
*/
void
ex_cd(exarg_T *eap)
***************
*** 7532,7550 ****
emsg(_(e_failed));
else
{
! int is_local_chdir = eap->cmdidx == CMD_lcd
|| eap->cmdidx == CMD_lchdir;
! post_chdir(is_local_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",
new_dir, FALSE, curbuf);
}
vim_free(tofree);
}
--- 7543,7571 ----
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. */
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);
}
***************
*** 9729,9740 ****
}
for (tabnr = 1; ; ++tabnr)
{
int need_tabnext = FALSE;
int cnr = 1;
if ((ssop_flags & SSOP_TABPAGES))
{
! tabpage_T *tp = find_tabpage(tabnr);
if (tp == NULL)
break; /* done all tab pages */
--- 9750,9762 ----
}
for (tabnr = 1; ; ++tabnr)
{
+ tabpage_T *tp = NULL;
int need_tabnext = FALSE;
int cnr = 1;
if ((ssop_flags & SSOP_TABPAGES))
{
! tp = find_tabpage(tabnr);
if (tp == NULL)
break; /* done all tab pages */
***************
*** 9833,9838 ****
--- 9855,9872 ----
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.).
*/
*** ../vim-8.1.1217/src/if_py_both.h 2019-03-30 12:51:18.626808012 +0100
--- src/if_py_both.h 2019-04-27 20:05:21.282555283 +0200
***************
*** 1032,1038 ****
Py_DECREF(newwd);
Py_XDECREF(todecref);
! post_chdir(FALSE);
if (VimTryEnd())
{
--- 1032,1038 ----
Py_DECREF(newwd);
Py_XDECREF(todecref);
! post_chdir(FALSE, FALSE);
if (VimTryEnd())
{
*** ../vim-8.1.1217/src/proto/eval.pro 2019-04-05 22:50:35.025737353 +0200
--- src/proto/eval.pro 2019-04-27 20:05:21.286555269 +0200
***************
*** 116,122 ****
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);
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);
--- 116,122 ----
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, 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);
*** ../vim-8.1.1217/src/proto/ex_docmd.pro 2019-04-27 13:03:20.004715961
+0200
--- src/proto/ex_docmd.pro 2019-04-27 20:05:21.286555269 +0200
***************
*** 37,43 ****
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 ex_cd(exarg_T *eap);
void do_sleep(long msec);
void ex_may_print(exarg_T *eap);
--- 37,43 ----
void tabpage_new(void);
void do_exedit(exarg_T *eap, win_T *old_curwin);
void free_cd_dir(void);
! 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);
*** ../vim-8.1.1217/src/structs.h 2019-04-27 13:03:20.008715938 +0200
--- src/structs.h 2019-04-27 20:05:21.286555269 +0200
***************
*** 2574,2579 ****
--- 2574,2582 ----
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]);
*** ../vim-8.1.1217/src/testdir/test_getcwd.vim 2019-01-09 23:00:57.997176121
+0100
--- src/testdir/test_getcwd.vim 2019-04-27 20:05:21.286555269 +0200
***************
*** 97,102 ****
--- 97,113 ----
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,112 ****
--- 121,264 ----
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
*** ../vim-8.1.1217/src/testdir/test_mksession.vim 2019-02-03
14:52:42.505867463 +0100
--- src/testdir/test_mksession.vim 2019-04-27 20:05:21.286555269 +0200
***************
*** 210,215 ****
--- 210,257 ----
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
*** ../vim-8.1.1217/src/window.c 2019-04-26 20:32:57.086296530 +0200
--- src/window.c 2019-04-27 20:05:21.286555269 +0200
***************
*** 3625,3630 ****
--- 3625,3632 ----
unref_var_dict(tp->tp_vars);
#endif
+ vim_free(tp->tp_localdir);
+
#ifdef FEAT_PYTHON
python_tabpage_free(tp);
#endif
***************
*** 3662,3667 ****
--- 3664,3671 ----
}
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,3844 ****
--- 3843,3851 ----
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,4461 ****
curwin->w_cursor.coladd = 0;
changed_line_abv_curs(); /* assume cursor position needs updating */
! if (curwin->w_localdir != NULL)
{
! /* Window 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];
--- 4458,4470 ----
curwin->w_cursor.coladd = 0;
changed_line_abv_curs(); /* assume cursor position needs updating */
! if (curwin->w_localdir != NULL || curtab->tp_localdir != NULL)
{
! 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,4469 ****
if (mch_dirname(cwd, MAXPATHL) == OK)
globaldir = vim_strsave(cwd);
}
! if (mch_chdir((char *)curwin->w_localdir) == 0)
shorten_fnames(TRUE);
}
else if (globaldir != NULL)
--- 4472,4483 ----
if (mch_dirname(cwd, MAXPATHL) == OK)
globaldir = vim_strsave(cwd);
}
! 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)
*** ../vim-8.1.1217/src/version.c 2019-04-27 19:15:41.856806819 +0200
--- src/version.c 2019-04-27 20:04:37.658747152 +0200
***************
*** 769,770 ****
--- 769,772 ----
{ /* Add new patch number below this line */
+ /**/
+ 1218,
/**/
--
WOMAN: Dennis, there's some lovely filth down here. Oh -- how d'you do?
ARTHUR: How do you do, good lady. I am Arthur, King of the Britons.
Who's castle is that?
WOMAN: King of the who?
The Quest for the Holy Grail (Monty Python)
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.