about summary refs log tree commit diff
path: root/Completion/Unix/Type/_canonical_paths
diff options
context:
space:
mode:
authorClint Adams <clint@users.sourceforge.net>2006-05-28 18:36:05 +0000
committerClint Adams <clint@users.sourceforge.net>2006-05-28 18:36:05 +0000
commit9ececd41799b66333c655f5de1f2a4f1c70f6d05 (patch)
tree11b5f11cec10eeeca55cbd7c697c64e93fe5767f /Completion/Unix/Type/_canonical_paths
parentad49fe14d71704c44c3cacc345b6e0a7619f6bea (diff)
downloadzsh-9ececd41799b66333c655f5de1f2a4f1c70f6d05.tar.gz
zsh-9ececd41799b66333c655f5de1f2a4f1c70f6d05.tar.xz
zsh-9ececd41799b66333c655f5de1f2a4f1c70f6d05.zip
22467: utility function which completes all paths given to it, and also
tries to offer completions which point to the same file as one of the paths
given.
Diffstat (limited to 'Completion/Unix/Type/_canonical_paths')
-rw-r--r--Completion/Unix/Type/_canonical_paths94
1 files changed, 94 insertions, 0 deletions
diff --git a/Completion/Unix/Type/_canonical_paths b/Completion/Unix/Type/_canonical_paths
new file mode 100644
index 000000000..c33892c84
--- /dev/null
+++ b/Completion/Unix/Type/_canonical_paths
@@ -0,0 +1,94 @@
+#autoload
+
+# This completion function completes all paths given to it, and also tries to
+# offer completions which point to the same file as one of the paths given
+# (relative path when an absolute path is given, and vice versa; when ..'s are
+# present in the word to be completed, and some paths got from symlinks.
+
+# Usage: _canonical_paths [-A var] [-N] [-MJV12nfX] tag desc paths...
+
+# -A, if specified, takes the paths from the array variable specified. Paths can
+# also be specified on the command line as shown above. -N, if specified,
+# prevents canonicalizing the paths given before using them for completion, in
+# case they are already so. `tag' and `desc' arguments are well, obvious :) In
+# addition, the options -M, -J, -V, -1, -2, -n, -F, -X are passed to compadd.
+
+local __index
+typeset -a __gopts __opts
+
+zparseopts -D -a __gopts M: J: V: 1 2 n F: X: A:=__opts N=__opts
+
+: ${1:=canonical-paths} ${2:=path}
+
+__index=$__opts[(I)-A]
+(( $__index )) && set -- $@ ${(P)__opts[__index+1]}
+
+local expl ret=1 tag=$1 desc=$2
+
+shift 2
+
+if (( ! $+commands[readlink] )); then
+  _wanted "$tag" expl "$desc" compadd $__gopts $@ && ret=0
+  return ret
+fi
+
+typeset -a matches files
+
+if (( $__opts[(I)-N] )); then
+  files=($@)
+else
+  for __index in $@; do
+    files+=$(readlink -qf $__index)
+  done
+fi
+
+_canonical_paths_add_paths () {
+  local origpref=$1 expref rltrim curpref canpref subdir
+  [[ $2 != add ]] && matches=()
+  expref=${~origpref}
+  [[ $origpref == (|*/). ]] && rltrim=.
+  curpref=${${expref%$rltrim}:-./}
+  canpref=$(readlink -qf $curpref)
+  if [[ $? -eq 0 ]]; then
+    [[ $curpref == */ && $canpref == *[^/] ]] && canpref+=/
+    canpref+=$rltrim
+    [[ $expref == *[^/] && $canpref == */ ]] && origpref+=/
+    matches+=(${${(M)files:#$canpref*}/$canpref/$origpref})
+  fi
+  for subdir in $expref?*(@); do
+    _canonical_paths_add_paths ${subdir/$expref/$origpref} add
+  done
+}
+
+local base=$PREFIX
+typeset -i blimit
+
+_canonical_paths_add_paths $base
+
+if [[ -z $base ]]; then
+  _canonical_paths_add_paths / add
+elif [[ $base == ..(/.(|.))#(|/) ]]; then
+
+  # This style controls how many parent directory links (..) to chase searching
+  # for possible completions. The default is 8. Note that this chasing is
+  # triggered only when the user enters atleast a .. and the path completed
+  # contains only . or .. components. A value of 0 turns off .. link chasing
+  # altogether.
+
+  zstyle -s ":completion:${curcontext}:$tag" \
+    canonical-paths-back-limit blimit || blimit=8
+
+  if [[ $base != */ ]]; then
+    [[ $base != *.. ]] && base+=.
+    base+=/
+  fi
+  until [[ $base.. -ef $base || blimit -le 0 ]]; do
+    base+=../
+    _canonical_paths_add_paths $base add
+    blimit+=-1
+  done
+fi
+
+_wanted "$tag" expl "$desc" compadd $__gopts -Q -U -a matches && ret=0
+
+return ret