summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-04-07 18:16:10 +0200
committerChristian Brabandt <cb@256bit.org>2024-04-07 18:16:10 +0200
commit9d956ee8eab64a0d412b045305fde5bc03d95d4a (patch)
treecf646584973d74b7d376f065c013d94667de7063
parenta44ced5763d377c71c96562b894c1c026ba89328 (diff)
patch 9.1.0272: autocmd may change cwd after :tcd and :lcdv9.1.0272
Problem: Autocommand may change currect directory after :tcd and :lcd. Solution: Also clear tp_localdir and w_localdir when using aucmd_win. (zeertzjq) closes: #14435 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/autocmd.c11
-rw-r--r--src/proto/window.pro1
-rw-r--r--src/structs.h1
-rw-r--r--src/testdir/test_autocmd.vim43
-rw-r--r--src/version.c2
-rw-r--r--src/window.c9
6 files changed, 62 insertions, 5 deletions
diff --git a/src/autocmd.c b/src/autocmd.c
index b1c74cb853..666cf45d30 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -1660,6 +1660,11 @@ aucmd_prepbuf(
win_init_popup_win(auc_win, buf);
+ // Make sure tp_localdir and globaldir are NULL to avoid a
+ // chdir() in win_enter_ext().
+ // win_init_popup_win() has already set w_localdir to NULL.
+ aco->tp_localdir = curtab->tp_localdir;
+ curtab->tp_localdir = NULL;
aco->globaldir = globaldir;
globaldir = NULL;
@@ -1773,6 +1778,12 @@ win_found:
vars_clear(&awp->w_vars->dv_hashtab); // free all w: variables
hash_init(&awp->w_vars->dv_hashtab); // re-use the hashtab
#endif
+ // If :lcd has been used in the autocommand window, correct current
+ // directory before restoring tp_localdir and globaldir.
+ if (awp->w_localdir != NULL)
+ win_fix_current_dir();
+ vim_free(curtab->tp_localdir);
+ curtab->tp_localdir = aco->tp_localdir;
vim_free(globaldir);
globaldir = aco->globaldir;
diff --git a/src/proto/window.pro b/src/proto/window.pro
index 9e66db5a7f..26c7040b8a 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -57,6 +57,7 @@ tabpage_T *win_find_tabpage(win_T *win);
win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, int up, long count);
win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, int left, long count);
void win_enter(win_T *wp, int undo_sync);
+void win_fix_current_dir(void);
win_T *buf_jump_open_win(buf_T *buf);
win_T *buf_jump_open_tab(buf_T *buf);
int win_unlisted(win_T *wp);
diff --git a/src/structs.h b/src/structs.h
index 3ce13ff0fb..f9a72e1454 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -4397,6 +4397,7 @@ typedef struct
int new_curwin_id; // ID of new curwin
int save_prevwin_id; // ID of saved prevwin
bufref_T new_curbuf; // new curbuf
+ char_u *tp_localdir; // saved value of tp_localdir
char_u *globaldir; // saved value of globaldir
int save_VIsual_active; // saved VIsual_active
int save_State; // saved State
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 50fdc41dc1..c7d2534a28 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -3727,6 +3727,49 @@ func Test_switch_window_in_autocmd_window()
call assert_false(bufexists('Xb.txt'))
endfunc
+" Test that using the autocommand window doesn't change current directory.
+func Test_autocmd_window_cwd()
+ let saveddir = getcwd()
+ call mkdir('Xcwd/a/b/c/d', 'pR')
+
+ new Xa.txt
+ tabnew
+ new Xb.txt
+
+ tabprev
+ cd Xcwd
+ call assert_match('/Xcwd$', getcwd())
+ call assert_match('\[global\] .*/Xcwd$', trim(execute('verbose pwd')))
+
+ autocmd BufEnter Xb.txt lcd ./a/b/c/d
+ doautoall BufEnter
+ au! BufEnter
+ call assert_match('/Xcwd$', getcwd())
+ call assert_match('\[global\] .*/Xcwd$', trim(execute('verbose pwd')))
+
+ tabnext
+ cd ./a
+ tcd ./b
+ lcd ./c
+ call assert_match('/Xcwd/a/b/c$', getcwd())
+ call assert_match('\[window\] .*/Xcwd/a/b/c$', trim(execute('verbose pwd')))
+
+ autocmd BufEnter Xa.txt call assert_match('Xcwd/a/b/c$', getcwd())
+ doautoall BufEnter
+ au! BufEnter
+ call assert_match('/Xcwd/a/b/c$', getcwd())
+ call assert_match('\[window\] .*/Xcwd/a/b/c$', trim(execute('verbose pwd')))
+ bwipe!
+ call assert_match('/Xcwd/a/b$', getcwd())
+ call assert_match('\[tabpage\] .*/Xcwd/a/b$', trim(execute('verbose pwd')))
+ bwipe!
+ call assert_match('/Xcwd/a$', getcwd())
+ call assert_match('\[global\] .*/Xcwd/a$', trim(execute('verbose pwd')))
+ bwipe!
+
+ call chdir(saveddir)
+endfunc
+
func Test_bufwipeout_changes_window()
" This should not crash, but we don't have any expectations about what
" happens, changing window in BufWipeout has unpredictable results.
diff --git a/src/version.c b/src/version.c
index 3b33ab176f..6d9a18c109 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 272,
+/**/
271,
/**/
270,
diff --git a/src/window.c b/src/window.c
index 9ffca77c92..7d78b5f29a 100644
--- a/src/window.c
+++ b/src/window.c
@@ -4437,8 +4437,7 @@ win_init_popup_win(win_T *wp, buf_T *buf)
++buf->b_nwindows;
win_init_empty(wp); // set cursor and topline to safe values
- // Make sure w_localdir and globaldir are NULL to avoid a chdir() in
- // win_enter_ext().
+ // Make sure w_localdir is NULL to avoid a chdir() in win_enter_ext().
VIM_CLEAR(wp->w_localdir);
}
@@ -5445,8 +5444,8 @@ win_enter(win_T *wp, int undo_sync)
* Used after making another window the current one: change directory if
* needed.
*/
- static void
-fix_current_dir(void)
+ void
+win_fix_current_dir(void)
{
if (curwin->w_localdir != NULL || curtab->tp_localdir != NULL)
{
@@ -5567,7 +5566,7 @@ win_enter_ext(win_T *wp, int flags)
}
#endif
- fix_current_dir();
+ win_fix_current_dir();
#ifdef FEAT_JOB_CHANNEL
entering_window(curwin);