mirror of
https://github.com/neovim/neovim.git
synced 2026-03-30 12:22:08 +00:00
Problem: With 'autochdir' win_execute() can corrupt the buffer name,
causing :write to use wrong path.
Solution: Save and restore b_fname when 'autochdir' is active
(Ingo Karkat).
This 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:
1. In the initial state after the :lcd .. we have curbuf->b_fname =
"Xsubdir/file".
2. do_autochdir() is invoked, temporarily undoing the :lcd .., changing
back into the Xsubdir/ subdirectory.
3. win_execute() switches windows, triggering win_enter_ext() →
win_fix_current_dir() → shorten_fnames(TRUE)
4. shorten_fnames() processes *all* buffers
5. shorten_buf_fname() makes the filename relative to the current
(wrong) directory; b_fname becomes "file" instead of "Xsubdir/file"
6. Directory restoration correctly restores working directory via
mch_chdir() (skipping a second do_autochdir() invocation because
apply_acd is FALSE), but b_fname remains corrupted, with the
"Xsubdir/" part missing.
7. 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.
closes: vim/vim#19343
abb4d74033
Co-authored-by: Ingo Karkat <swdev@ingo-karkat.de>
31 lines
718 B
C
31 lines
718 B
C
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "nvim/buffer_defs.h"
|
|
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
|
|
#include "nvim/os/os_defs.h"
|
|
#include "nvim/pos_defs.h"
|
|
#include "nvim/types_defs.h"
|
|
|
|
/// Structure used by switch_win() to pass values to restore_win()
|
|
typedef struct {
|
|
win_T *sw_curwin;
|
|
tabpage_T *sw_curtab;
|
|
bool sw_same_win; ///< VIsual_active was not reset
|
|
bool sw_visual_active;
|
|
} switchwin_T;
|
|
|
|
/// Structure used by win_execute_before() to pass values to win_execute_after()
|
|
typedef struct {
|
|
win_T *wp;
|
|
pos_T curpos;
|
|
char cwd[MAXPATHL];
|
|
int cwd_status;
|
|
bool apply_acd;
|
|
char *save_sfname;
|
|
switchwin_T switchwin;
|
|
} win_execute_T;
|
|
|
|
#include "eval/window.h.generated.h"
|