Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

ignore-parents style broken for cd



The ignore-parents style doesn't work for the cd command:

$ zstyle ':completion:*' ignore-parents pwd parent
$ mkdir junk junk/foo junk/bar
$ cd junk/foo
$ ls ../<TAB>       # only 'bar' is offered; OK
$ cd ../<TAB>       # both 'foo' and 'bar' are offered

This happens after the following commit:

commit 012668e14ec7305c404975da8c5ba648c1586a82
Author: Barton E. Schaefer <schaefer@xxxxxxx>
Date:   Tue Sep 10 08:14:37 2013 -0700

    31714: handle ".." properly when $PWD or the path prefix traverses a symbolic link.

diff --git a/Completion/Zsh/Command/_cd b/Completion/Zsh/Command/_cd
index 476947f..a5d328f 100644
--- a/Completion/Zsh/Command/_cd
+++ b/Completion/Zsh/Command/_cd
@@ -51,6 +51,18 @@ else
     _directory_stack && ret=0
   fi
 
+  local -a tmpWpath
+  if [[ $PREFIX = (|*/)../* ]]; then
+    local tmpprefix
+    # Use cd in a subshell to properly [not] resolve symlinks
+    tmpprefix=$(cd ${PREFIX%/*} >&/dev/null && print $PWD)
(snip)

But the actual problem may be not in _cd but in either _path_files
or compadd (or 'compfiles -i' ?).

_path_files calls compadd in a way something like the following:

_comp_ignore=( /path/to/junk/foo )
words=( foo bar )
compadd -f -F _comp_ignore -W /path/to/junk/ -a words

but compadd does not remove 'foo' from the words.
It seems we need to set _comp_ignore=( foo ) instead.
Is this the expected behavior of compadd?
If so, then _path_files may need some fix?

The patch below is my try, but I don't (and will never)
understand any details of _path_files.

P.S.
I also didn't understand the logic at line 569:
      (( $#_comp_ignore && $mopts[(I)-F] )) ||
and modified it as below.


diff --git a/Completion/Unix/Type/_path_files b/Completion/Unix/Type/_path_files
index aa58ea0..85feae5 100644
--- a/Completion/Unix/Type/_path_files
+++ b/Completion/Unix/Type/_path_files
@@ -564,9 +564,10 @@ for prepath in "$prepaths[@]"; do
           ( "$ignpar" != *dir* || "$pats" = '*(-/)' ) &&
           ( "$ignpar" != *..* || "$tmp1[1]" = *../* ) ]]; then
 
-      compfiles -i tmp1 _comp_ignore "$ignpar" "$prepath$realpath$donepath"
+      compfiles -i tmp1 ignore "$ignpar" "$prepath$realpath$donepath"
+      _comp_ignore+=( ${(@)ignore#$prepath$realpath$donepath} )
 
-      (( $#_comp_ignore && $mopts[(I)-F] )) ||
+      (( $#_comp_ignore && ! $mopts[(I)-F] )) &&
           mopts=( "$mopts[@]" -F _comp_ignore )
     fi
 





Messages sorted by: Reverse Date, Date, Thread, Author