From bb75610d998cdd9439ab84c2ac92ec2ac456c76d Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 4 Jul 2025 13:44:39 +0800 Subject: [PATCH] vim-patch:9.1.1507: symlinks are resolved on :cd commands (#34758) Problem: File paths change from symlink to target path after :cd command when editing files through symbolic links Solution: Add "~" flag to 'cpoptions' to control symlink resolution. When not included (default), symlinks are resolved maintaining backward compatibility. When included, symlinks are preserved providing the improved behavior. (glepnir) related: neovim/neovim#15695 closes: vim/vim#17628 https://github.com/vim/vim/commit/4ade668fb62ebf3f8be537fe451caed6bd1eba9a --- runtime/doc/options.txt | 7 ++++ runtime/lua/vim/_meta/options.lua | 7 ++++ src/nvim/ex_docmd.c | 2 +- src/nvim/option_vars.h | 3 +- src/nvim/options.lua | 7 ++++ test/old/testdir/test_cd.vim | 63 +++++++++++++++++++++++++++++++ test/old/testdir/test_options.vim | 6 +-- 7 files changed, 90 insertions(+), 5 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 89bd974476..ad58a74b31 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1962,6 +1962,13 @@ A jump table for the options with a short description can be found at |Q_op|. character, the cursor won't move. When not included, the cursor would skip over it and jump to the following occurrence. + *cpo-~* + ~ When included, don't resolve symbolic links when + changing directory with |:cd|, |:lcd|, or |:tcd|. + This preserves the symbolic link path in buffer names + and when displaying the current directory. When + excluded (default), symbolic links are resolved to + their target paths. *cpo-_* _ When using |cw| on a word, do not include the whitespace following the word in the motion. diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 2c6d3e6048..585a02f330 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -1515,6 +1515,13 @@ vim.bo.ci = vim.bo.copyindent --- character, the cursor won't move. When not included, --- the cursor would skip over it and jump to the --- following occurrence. +--- *cpo-~* +--- ~ When included, don't resolve symbolic links when +--- changing directory with `:cd`, `:lcd`, or `:tcd`. +--- This preserves the symbolic link path in buffer names +--- and when displaying the current directory. When +--- excluded (default), symbolic links are resolved to +--- their target paths. --- *cpo-_* --- _ When using `cw` on a word, do not include the --- whitespace following the word in the motion. diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index b5418c3bb8..55d5efe234 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6016,7 +6016,7 @@ static void post_chdir(CdScope scope, bool trigger_dirchanged) } last_chdir_reason = NULL; - shorten_fnames(true); + shorten_fnames(vim_strchr(p_cpo, CPO_NOSYMLINKS) == NULL); if (trigger_dirchanged) { do_autocmd_dirchanged(cwd, scope, kCdCauseManual, false); diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index 16b009fa73..09b3a9637b 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -121,10 +121,11 @@ #define CPO_REGAPPEND '>' // insert NL when appending to a register #define CPO_SCOLON ';' // using "," and ";" will skip over char if // cursor would not move +#define CPO_NOSYMLINKS '~' // don't resolve symlinks when changing directory #define CPO_CHANGEW '_' // "cw" special-case // default values for Vim and Vi #define CPO_VIM "aABceFs_" -#define CPO_VI "aAbBcCdDeEfFiIJKlLmMnoOpPqrRsStuvWxXyZ$!%+>;_" +#define CPO_VI "aAbBcCdDeEfFiIJKlLmMnoOpPqrRsStuvWxXyZ$!%+>;~_" // characters for p_ww option: #define WW_ALL "bshl<>[]~" diff --git a/src/nvim/options.lua b/src/nvim/options.lua index bae45ea7ca..2562c56972 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2002,6 +2002,13 @@ local options = { character, the cursor won't move. When not included, the cursor would skip over it and jump to the following occurrence. + *cpo-~* + ~ When included, don't resolve symbolic links when + changing directory with |:cd|, |:lcd|, or |:tcd|. + This preserves the symbolic link path in buffer names + and when displaying the current directory. When + excluded (default), symbolic links are resolved to + their target paths. *cpo-_* _ When using |cw| on a word, do not include the whitespace following the word in the motion. diff --git a/test/old/testdir/test_cd.vim b/test/old/testdir/test_cd.vim index dd92fc6c38..8a7baad45e 100644 --- a/test/old/testdir/test_cd.vim +++ b/test/old/testdir/test_cd.vim @@ -253,4 +253,67 @@ func Test_getcwd_actual_dir() call chdir(startdir) endfunc +func Test_cd_preserve_symlinks() + " Test new behavior: preserve symlinks when cpo-=~ + set cpoptions+=~ + + let savedir = getcwd() + call mkdir('Xsource', 'R') + call writefile(['abc'], 'Xsource/foo.txt', 'D') + + if has("win32") + silent !mklink /D Xdest Xsource + else + silent !ln -s Xsource Xdest + endif + if v:shell_error + call delete('Xsource', 'rf') + throw 'Skipped: cannot create symlinks' + endif + + edit Xdest/foo.txt + let path_before = expand('%') + call assert_match('Xdest[/\\]foo\.txt$', path_before) + + cd . + let path_after = expand('%') + call assert_equal(path_before, path_after) + call assert_match('Xdest[/\\]foo\.txt$', path_after) + + bwipe! + set cpoptions& + call delete('Xdest', 'rf') + call delete('Xsource', 'rf') + call chdir(savedir) +endfunc + +func Test_cd_symlinks() + CheckNotMSWindows + + let savedir = getcwd() + call mkdir('Xsource', 'R') + call writefile(['abc'], 'Xsource/foo.txt', 'D') + + silent !ln -s Xsource Xdest + if v:shell_error + call delete('Xsource', 'rf') + throw 'Skipped: cannot create symlinks' + endif + + edit Xdest/foo.txt + let path_before = expand('%') + call assert_match('Xdest[/\\]foo\.txt$', path_before) + + cd . + let path_after = expand('%') + call assert_match('Xsource[/\\]foo\.txt$', path_after) + call assert_notequal(path_before, path_after) + + bwipe! + set cpoptions& + call delete('Xdest', 'rf') + call delete('Xsource', 'rf') + call chdir(savedir) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index 391817b441..0e7138913b 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -2265,7 +2265,7 @@ func Test_VIM_POSIX() qall [CODE] if RunVim([], after, '') - call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>#{|&/\.;', + call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>#{|&/\.;~', \ 'AS'], readfile('X_VIM_POSIX')) endif @@ -2527,8 +2527,8 @@ func Test_string_option_revert_on_failure() \ ['completeopt', 'preview', 'a123'], "\ ['completepopup', 'width:20', 'border'], \ ['concealcursor', 'v', 'xyz'], - "\ ['cpoptions', 'HJ', '~'], - \ ['cpoptions', 'J', '~'], + "\ ['cpoptions', 'HJ', 'Q'], + \ ['cpoptions', 'J', 'Q'], "\ ['cryptmethod', 'zip', 'a123'], \ ['cursorlineopt', 'screenline', 'a123'], \ ['debug', 'throw', 'a123'],