From 4ade668fb62ebf3f8be537fe451caed6bd1eba9a Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 3 Jul 2025 20:41:23 +0200 Subject: [PATCH] patch 9.1.1507: symlinks are resolved on :cd commands 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: #17628 Signed-off-by: glepnir Signed-off-by: Christian Brabandt --- runtime/doc/options.txt | 11 +++++-- runtime/doc/tags | 1 + runtime/doc/version9.txt | 2 ++ src/ex_docmd.c | 2 +- src/option.h | 3 +- src/testdir/test_cd.vim | 63 ++++++++++++++++++++++++++++++++++++ src/testdir/test_options.vim | 4 +-- src/version.c | 2 ++ 8 files changed, 82 insertions(+), 6 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index b3c5697cfc..cf064e17fd 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 9.1. Last change: 2025 Jul 01 +*options.txt* For Vim version 9.1. Last change: 2025 Jul 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2390,7 +2390,7 @@ A jump table for the options with a short description can be found at |Q_op|. *'cpoptions'* *'cpo'* *cpo* 'cpoptions' 'cpo' string (Vim default: "aABceFsz", - Vi default: all flags, except "#{|&/\." + Vi default: all flags, except "#{|&/\.~" |$VIM_POSIX|: all flags) global A sequence of single character flags. When a character is present @@ -2680,6 +2680,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. POSIX flags. These are not included in the Vi default value, except when $VIM_POSIX was set on startup. |posix| diff --git a/runtime/doc/tags b/runtime/doc/tags index 71a961697b..6b363dbaa9 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -6795,6 +6795,7 @@ cpo-x options.txt /*cpo-x* cpo-y options.txt /*cpo-y* cpo-z options.txt /*cpo-z* cpo-{ options.txt /*cpo-{* +cpo-~ options.txt /*cpo-~* cpp.vim syntax.txt /*cpp.vim* crash-recovery recover.txt /*crash-recovery* creating-menus gui.txt /*creating-menus* diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index fcd3b9f343..75d14011ab 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -41643,6 +41643,8 @@ Options: ~ - 'completeopt' is now a |global-local| option. - add 'cpoptions' flag "z" |cpo-z|, to disable some (traditional) vi behaviour/inconsistency (see |d-special| and |cw|). +- add 'cpoptions' flag "~" |cpo-~| to disable resolving symlinks on |:cd| + commands - new option values for 'fillchars': "trunc" - configure truncation indicator, 'pummaxwidth' "truncrl" - like "trunc" but in 'rl' mode, 'pummaxwidth' diff --git a/src/ex_docmd.c b/src/ex_docmd.c index ba0bff4668..b985e2ba2b 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -8029,7 +8029,7 @@ post_chdir(cdscope_T scope) } last_chdir_reason = NULL; - shorten_fnames(TRUE); + shorten_fnames(vim_strchr(p_cpo, CPO_NOSYMLINKS) == NULL); } /* diff --git a/src/option.h b/src/option.h index 4ed117c705..5590e5635b 100644 --- a/src/option.h +++ b/src/option.h @@ -231,10 +231,11 @@ typedef enum { #define CPO_CHDIR '.' // don't chdir if buffer is modified #define CPO_SCOLON ';' // using "," and ";" will skip over char if // cursor would not move +#define CPO_NOSYMLINKS '~' // don't resolve symlinks when changing directory // default values for Vim, Vi and POSIX #define CPO_VIM "aABceFsz" #define CPO_VI "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>;" -#define CPO_ALL "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>#{|&/\\.;" +#define CPO_ALL "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>#{|&/\\.;~" // characters for p_ww option: #define WW_ALL "bshl<>[]~" diff --git a/src/testdir/test_cd.vim b/src/testdir/test_cd.vim index 13a3eba370..85494d386a 100644 --- a/src/testdir/test_cd.vim +++ b/src/testdir/test_cd.vim @@ -252,4 +252,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/src/testdir/test_options.vim b/src/testdir/test_options.vim index cb5636ee1d..21e4a03579 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -2273,7 +2273,7 @@ func Test_VIM_POSIX() qall [CODE] if RunVim([], after, '') - call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>#{|&/\.;', + call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>#{|&/\.;~', \ 'AS'], readfile('X_VIM_POSIX')) endif @@ -2528,7 +2528,7 @@ func Test_string_option_revert_on_failure() \ ['completeopt', 'popup', 'a123'], \ ['completepopup', 'width:20', 'border'], \ ['concealcursor', 'v', 'xyz'], - \ ['cpoptions', 'HJ', '~'], + \ ['cpoptions', 'HJ', 'Q'], \ ['cryptmethod', 'zip', 'a123'], \ ['cursorlineopt', 'screenline', 'a123'], \ ['debug', 'throw', 'a123'], diff --git a/src/version.c b/src/version.c index d5a882da6b..9d27681688 100644 --- a/src/version.c +++ b/src/version.c @@ -719,6 +719,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1507, /**/ 1506, /**/