forked from aniani/vim
patch 8.1.1218: cannot set a directory for a tab page
Problem: Cannot set a directory for a tab page. Solution: Add the tab-local directory. (Yegappan Lakshmanan, closes #4212)
This commit is contained in:
parent
2155a6abaa
commit
00aa069db8
@ -1,4 +1,4 @@
|
||||
*autocmd.txt* For Vim version 8.1. Last change: 2019 Apr 08
|
||||
*autocmd.txt* For Vim version 8.1. Last change: 2019 Apr 27
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -690,13 +690,14 @@ DiffUpdated After diffs have been updated. Depending on
|
||||
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.
|
||||
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`
|
||||
"global" to trigger on `:cd`
|
||||
"auto" to trigger on 'autochdir'.
|
||||
"drop" to trigger on editing a file
|
||||
"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
|
||||
|
@ -1304,9 +1304,10 @@ use has("browsefilter"): >
|
||||
==============================================================================
|
||||
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".
|
||||
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,6 +1335,17 @@ present in 'cpoptions' and "!" is not used in the command.
|
||||
*: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,17 +1360,26 @@ present in 'cpoptions' and "!" is not used in the command.
|
||||
: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.
|
||||
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 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.
|
||||
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
|
||||
|
@ -2398,6 +2398,7 @@ has({feature}) Number |TRUE| if feature {feature} supported
|
||||
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
|
||||
@ -4918,9 +4919,28 @@ getcwd([{winnr} [, {tabnr}]])
|
||||
directory. See also |haslocaldir()|.
|
||||
|
||||
With {winnr} and {tabnr} return the local current directory of
|
||||
the window in the specified tab page.
|
||||
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}.
|
||||
@ -5478,16 +5498,39 @@ has_key({dict}, {key}) *has_key()*
|
||||
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.
|
||||
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)
|
||||
|
@ -1623,6 +1623,8 @@ tag command action ~
|
||||
|: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
|
||||
|
@ -1455,9 +1455,9 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
{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.
|
||||
|: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
|
||||
|
@ -202,14 +202,28 @@ the other window. This is called a local directory. >
|
||||
: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
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -766,7 +766,7 @@ System functions and manipulation of files:
|
||||
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|
|
||||
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
|
||||
|
18
src/eval.c
18
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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.).
|
||||
*/
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -767,6 +767,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1218,
|
||||
/**/
|
||||
1217,
|
||||
/**/
|
||||
|
24
src/window.c
24
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user