This problem has been in Vim since the introduction of win_execute(), but it's only encountered when 'autochdir' is set (which most users don't) and you do a local override of the working directory. Unfortunately, I've been encountering that frequently, because my configuration switches to the parent directory for editing Git commit messages (so I can directly reference files from the project root instead of the useless .git/ subdir where the message is created in), and I use several custom completions that inspect other buffers via win_execute(). If you :wq after a completion, the COMMIT_EDITMSG file is written to the project root, and the Git command aborts or uses stale data! I've finally dug into this, and found a simple fix for this cornercase, that I've successfully been using for the past week.
The problem is caused by a bad interaction of the 'autochdir' behavior, overriding of the current directory via :lchdir, and the temporary window switching done by win_execute(), manifesting when e.g. a custom completion inspects other buffers.
:lcd .. we have curbuf->b_fname = "Xsubdir/file".do_autochdir() is invoked, temporarily undoing the :lcd .., changing back into the Xsubdir/ subdirectory.win_execute() switches windows, triggering win_enter_ext() → win_fix_current_dir() → shorten_fnames(TRUE)shorten_fnames() processes all buffersshorten_buf_fname() makes the filename relative to the current (wrong) directory; b_fname becomes file instead of Xsubdir/filemch_chdir() (skipping a second do_autochdir() invocation because apply_acd is FALSE), but b_fname remains corrupted, with the Xsubdir/ part missing.expand('%:p') (and commands like :write) continue to use the corrupted filename, resolving to a wrong path that's missing the Xsubdir/ part.To fix the problem the short filename is saved if its in effect (i.e. pointed to by curbuf->b_fname) and 'autochdir' happened. It's then restored in case of a local cwd override. The conditions limit this workaround to when 'autochdir' is active and overridden by a :lchdir.
The added test reproduces the problem and verifies the fix with a minimal setup using just one buffer and two split windows.
https://github.com/vim/vim/pull/19343
(2 files)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@zeertzjq commented on this pull request.
In src/evalwindow.c:
> @@ -732,6 +732,7 @@ f_win_execute(typval_T *argvars, typval_T *rettv)
# ifdef FEAT_AUTOCHDIR
char_u autocwd[MAXPATHL];
int apply_acd = FALSE;
+ char_u *save_sfname;
⬇️ Suggested change
- char_u *save_sfname; + char_u *save_sfname = NULL;
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@inkarkat pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Thanks, hm, doesn't that leak memory and you need to free curbuf->b_sfname before re-assigning it?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
thanks
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()