Teach cd completions about logical paths

Prior to this fix, cding into a symlink and then completing .. would complete
from the physical directory instead of the logical directory, which could not
actually be cd'd to. Teach cd completiond to use the logical directory.
This commit is contained in:
ridiculousfish
2018-11-03 13:30:55 -07:00
parent cf01694def
commit 182d7ce732
5 changed files with 63 additions and 3 deletions

View File

@@ -45,7 +45,7 @@ enum {
/// EXPAND_FUZZY_MATCH is set.
EXPAND_NO_FUZZY_DIRECTORIES = 1 << 10,
/// Do expansions specifically to support cd. This means using CDPATH as a list of potential
/// working directories.
/// working directories, and to use logical instead of physical paths.
EXPAND_SPECIAL_FOR_CD = 1 << 11,
/// Do expansions specifically for cd autosuggestion. This is to differentiate between cd
/// completions and cd autosuggestions.

View File

@@ -574,6 +574,9 @@ class wildcard_expander_t {
wcstring abs_path = this->working_directory;
append_path_component(abs_path, filepath);
// We must normalize the path to allow 'cd ..' to operate on logical paths.
if (flags & EXPAND_SPECIAL_FOR_CD) abs_path = normalize_path(abs_path);
size_t before = this->resolved_completions->size();
if (wildcard_test_flags_then_complete(abs_path, filename, wildcard.c_str(), this->flags,
this->resolved_completions)) {
@@ -591,8 +594,7 @@ class wildcard_expander_t {
}
// Implement EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST by descending the deepest unique
// hierarchy we
// can, and then appending any components to each new result.
// hierarchy we can, and then appending any components to each new result.
// Only descend deepest unique for cd autosuggest and not for cd tab completion
// (issue #4402).
if (flags & EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST) {
@@ -613,6 +615,16 @@ class wildcard_expander_t {
DIR *open_dir(const wcstring &base_dir) const {
wcstring path = this->working_directory;
append_path_component(path, base_dir);
if (flags & EXPAND_SPECIAL_FOR_CD) {
// cd operates on logical paths.
// for example, cd ../<tab> should complete "without resolving symlinks".
path = normalize_path(path);
} else {
// Other commands operate on physical paths.
if (auto tmp = wrealpath(path)) {
path = tmp.acquire();
}
}
return wopendir(path);
}

View File

@@ -1,3 +1,6 @@
####################
# cd symlink non-resolution
####################
# cd symlink completion

View File

@@ -7,3 +7,32 @@ test "$PWD" = "$link" || echo "\$PWD != \$link:"\n "\$PWD: $PWD"\n "\$link:
test (pwd) = "$link" || echo "(pwd) != \$link:"\n "\$PWD: "(pwd)\n "\$link: $link"\n
test (pwd -P) = "$real" || echo "(pwd -P) != \$real:"\n "\$PWD: $PWD"\n "\$real: $real"\n
test (pwd -P -L) = "$link" || echo "(pwd -P -L) != \$link:"\n "\$PWD: $PWD"\n "\$link: $link"\n
logmsg cd symlink completion
# Create a symlink and verify logical completion.
# create directory $base/through/the/looking/glass
# symlink $base/somewhere/teleport -> $base/through/the/looking/glass
# verify that .. completions work
set -l base /tmp/cdcomp_test/
rm -Rf $base
mkdir -p $base
cd $base
mkdir -p $base/through/the/looking/glass
mkdir -p $base/somewhere
mkdir $base/somewhere/a1
mkdir $base/somewhere/a2
mkdir $base/somewhere/a3
touch $base/through/the/looking/b(seq 1 3)
mkdir $base/through/the/looking/d1
mkdir $base/through/the/looking/d2
mkdir $base/through/the/looking/d3
ln -s $base/through/the/looking/glass $base/somewhere/rabbithole
cd $base/somewhere/rabbithole
echo "ls:"
complete -C'ls ../'
echo "cd:"
complete -C'cd ../'
rm -Rf $base

View File

@@ -1,3 +1,19 @@
####################
# cd symlink non-resolution
####################
# cd symlink completion
ls:
../b1
../b2
../b3
../d1/
../d2/
../d3/
../glass/
cd:
../a1/
../a2/
../a3/
../rabbithole/