about summary refs log tree commit diff
path: root/Completion
diff options
context:
space:
mode:
authorOliver Kiddle <opk@users.sourceforge.net>2003-02-28 13:50:44 +0000
committerOliver Kiddle <opk@users.sourceforge.net>2003-02-28 13:50:44 +0000
commit79d0de7c3ad8626d507b50176a80cf7ecb6f3996 (patch)
tree7009741bcfcf45c42ddea3be5a48807bc10f2ea9 /Completion
parent937e1b9f795e5fa3d605ae908ad96757e38014f7 (diff)
downloadzsh-79d0de7c3ad8626d507b50176a80cf7ecb6f3996.tar.gz
zsh-79d0de7c3ad8626d507b50176a80cf7ecb6f3996.tar.xz
zsh-79d0de7c3ad8626d507b50176a80cf7ecb6f3996.zip
merge changes from 4.1
Diffstat (limited to 'Completion')
-rw-r--r--Completion/Base/Utility/_multi_parts254
-rw-r--r--Completion/Unix/Command/_tar171
-rw-r--r--Completion/Unix/Type/_tar_archive26
3 files changed, 451 insertions, 0 deletions
diff --git a/Completion/Base/Utility/_multi_parts b/Completion/Base/Utility/_multi_parts
new file mode 100644
index 000000000..615ef79f2
--- /dev/null
+++ b/Completion/Base/Utility/_multi_parts
@@ -0,0 +1,254 @@
+#autoload
+
+# This gets two arguments, a separator (which should be only one
+# character) and an array. As usual, the array may be given by it's
+# name or literal as in `(foo bar baz)' (words separated by spaces in
+# parentheses).
+# The parts of words from the array that are separated by the
+# separator character are then completed independently.
+
+local sep pref npref i tmp2 group expl menu pre suf opre osuf orig cpre
+local opts sopts matcher imm
+typeset -U tmp1 matches
+
+# Get the options.
+
+zparseopts -D -a sopts \
+    'J+:=group' 'V+:=group' 'X+:=expl' 'P:=opts' 'F:=opts' \
+    S: r: R: q 1 2 n f 'M+:=matcher' 'i=imm'
+
+sopts=( "$sopts[@]" "$opts[@]" )
+if (( $#matcher )); then
+  matcher="${matcher[2]}"
+else
+  matcher=
+fi
+
+# Get the arguments, first the separator, then the array. The array is 
+# stored in `tmp1'. Further on the array `matches' will always contain
+# those words from the original array that still match everything we have
+# tried to match while we walk through the string from the line.
+
+sep="$1"
+if [[ "${2[1]}" = '(' ]]; then
+  tmp1=( ${=2[2,-2]} )
+else
+  tmp1=( "${(@P)2}" )
+fi
+
+# In `pre' and `suf' we will hold the prefix and the suffix from the
+# line while we walk through them. The original string are used 
+# temporarily for matching.
+
+pre="$PREFIX"
+suf="$SUFFIX"
+opre="$PREFIX"
+osuf="$SUFFIX"
+orig="$PREFIX$SUFFIX"
+
+# Special handling for menu completion?
+
+[[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
+   ( $#compstate[pattern_match] -ne 0 &&
+     "$orig" != "${orig:q}" ) ]] && menu=yes
+
+# In `pref' we collect the unambiguous prefix path.
+
+pref=''
+
+# If the string from the line matches at least one of the strings,
+# we use only the matching strings.
+
+compadd -O matches -M "r:|${sep}=* r:|=* $matcher" -a tmp1
+
+(( $#matches )) || matches=( "$tmp1[@]" )
+
+while true; do
+
+  # Get the prefix and suffix for matching.
+
+  if [[ "$pre" = *${sep}* ]]; then
+    PREFIX="${pre%%${sep}*}"
+    SUFFIX=""
+  else
+    PREFIX="${pre}"
+    SUFFIX="${suf%%${sep}*}"
+  fi
+
+  # Check if the component for some of the possible matches is equal
+  # to the string from the line. If there are such strings, we directly
+  # use the stuff from the line. This avoids having `foo' complete to
+  # both `foo' and `foobar'.
+
+  if [[ -n "$PREFIX$SUFFIX" || "$pre" = ${sep}* ]]; then
+    tmp1=( "${(@M)matches:#${PREFIX}${SUFFIX}${sep}*}" )
+  else
+    tmp1=()
+  fi
+
+  if (( $#tmp1 )); then
+    npref="${PREFIX}${SUFFIX}${sep}"
+  else
+    # No exact match, see how many strings match what's on the line.
+
+    builtin compadd -O tmp1 -M "r:|${sep}=* r:|=* $matcher" - "${(@)${(@)matches%%${sep}*}:#}"
+
+    [[ $#tmp1 -eq 0 && -n "$_comp_correct" ]] &&
+      compadd -O tmp1 -M "r:|${sep}=* r:|=* $matcher" - "${(@)${(@)matches%%${sep}*}:#}"
+
+    if [[ $#tmp1 -eq 1 ]]; then
+
+      # Only one match. If there are still separators from the line
+      # we just accept this component. Otherwise we insert what we 
+      # have collected, probably giving it a separator character
+      # as a suffix.
+
+      if [[ "$pre$suf" = *${sep}* ]]; then
+        npref="${tmp1[1]}${sep}"
+      else
+        matches=( "${(@M)matches:#${tmp1[1]}*}" )
+
+	PREFIX="${cpre}${pre}"
+	SUFFIX="$suf"
+
+	if [[ $#imm -ne 0 && $#matches -eq 1 ]] ||
+           zstyle -t ":completion:${curcontext}:" expand suffix; then
+	  compadd "$group[@]" "$expl[@]" "$sopts[@]" \
+                  -M "r:|${sep}=* r:|=* $matcher" - $pref$matches
+        else
+	  if (( $matches[(I)${tmp1[1]}${sep}*] )); then
+	    compadd "$group[@]" "$expl[@]" -p "$pref" -r "$sep" -S "$sep" "$opts[@]" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "$tmp1[1]"
+          else
+	    compadd "$group[@]" "$expl[@]" -p "$pref" "$sopts[@]" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "$tmp1[1]"
+          fi
+        fi
+	return
+      fi
+    elif (( $#tmp1 )); then
+      local ret=1
+
+      # More than one match. First we get all strings that match the
+      # rest from the line.
+
+      PREFIX="$pre"
+      SUFFIX="$suf"
+      compadd -O matches -M "r:|${sep}=* r:|=* $matcher" -a matches
+
+      if [[ "$pre" = *${sep}* ]]; then
+ 	PREFIX="${cpre}${pre%%${sep}*}"
+	SUFFIX="${sep}${pre#*${sep}}${suf}"
+      else
+        PREFIX="${cpre}${pre}"
+	SUFFIX="$suf"
+      fi
+
+      matches=( "${(@M)matches:#(${(j:|:)~tmp1})*}" )
+
+      if ! zstyle -t ":completion:${curcontext}:" expand suffix ||
+         [[ -n "$menu" || -z "$compstate[insert]" ]]; then
+
+        # With menu completion we add only the ambiguous component with
+        # the prefix collected and a separator for the matches that
+        # have more components.
+
+        tmp2="$pre$suf"
+        if [[ "$tmp2" = *${sep}* ]]; then
+          tmp2=(-s "${sep}${tmp2#*${sep}}")
+        else
+	  tmp2=()
+        fi
+
+
+        compadd "$group[@]" "$expl[@]" -r "$sep" -S "$sep" "$opts[@]" \
+	        -p "$pref" "$tmp2[@]" -M "r:|${sep}=* r:|=* $matcher" - \
+                "${(@)${(@)${(@M)matches:#*${sep}}%%${sep}*}:#}" && ret=0
+        (( $matches[(I)${sep}*] )) &&
+            compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" \
+	            -p "$pref" \
+                    -M "r:|${sep}=* r:|=* $matcher" - "$sep" && ret=0
+        compadd "$group[@]" "$expl[@]" -r "$sep" -S "$sep" "$opts[@]" \
+                -p "$pref" "$tmp2[@]" -M "r:|${sep}=* r:|=* $matcher" - \
+                "${(@)${(@)${(@M)matches:#*?${sep}?*}%%${sep}*}:#}" && ret=0
+        compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" -p "$pref" "$tmp2[@]" \
+                -M "r:|${sep}=* r:|=* $matcher" - \
+                "${(@)matches:#*${sep}*}" && ret=0
+      else
+        # With normal completion we add all matches one-by-one with
+	# the unmatched part as a suffix. This will insert the longest
+	# unambiguous string for all matching strings.
+
+        compadd "$group[@]" "$expl[@]" "$opts[@]" \
+	        -p "$pref" -s "${i#*${sep}}" \
+                -M "r:|${sep}=* r:|=* $matcher" - \
+                "${(@)${(@)${(@M)matches:#*${sep}*}%%${sep}*}:#}" && ret=0
+        compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" -p "$pref" \
+                -M "r:|${sep}=* r:|=* $matcher" - \
+                "${(@)matches:#*${sep}*}" && ret=0
+      fi
+      return ret
+    else
+      # We are here if no string matched what's on the line. In this
+      # case we insert the expanded prefix we collected if it differs
+      # from the original string from the line.
+
+      { ! zstyle -t ":completion:${curcontext}:" expand prefix ||
+        [[ "$orig" = "$pref$pre$suf" ]] } && return 1
+
+      PREFIX="${cpre}${pre}"
+      SUFFIX="$suf"
+
+      if [[ -n "$suf" ]]; then
+        compadd "$group[@]" "$expl[@]" -s "$suf" "$sopts[@]" \
+                -M "r:|${sep}=* r:|=* $matcher" - "$pref$pre"
+      else
+        compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" \
+                -M "r:|${sep}=* r:|=* $matcher" - "$pref$pre"
+      fi
+      return
+    fi
+  fi
+
+  # We just accepted and/or expanded a component from the line. We
+  # remove it from the matches (using only those that have a least
+  # the skipped string) and ad it the `pref'.
+
+  matches=( "${(@)${(@)${(@M)matches:#${npref}*}#*${sep}}:#}" )
+  pref="$pref$npref"
+
+  # Now we set `pre' and `suf' to their new values.
+
+  if [[ "$pre" = *${sep}* ]]; then
+    cpre="${cpre}${pre%%${sep}*}${sep}"
+    pre="${pre#*${sep}}"
+  elif [[ "$suf" = *${sep}* ]]; then
+    cpre="${cpre}${pre}${suf%%${sep}*}${sep}"
+    pre="${suf#*${sep}}"
+    suf=""
+  else
+    # The string from the line is fully handled. If we collected an
+    # unambiguous prefix and that differs from the original string,
+    # we insert it.
+
+    PREFIX="${opre}${osuf}"
+    SUFFIX=""
+
+    if [[ -n "$pref" && "$orig" != "$pref" ]]; then
+      if [[ "$pref" = *${sep}*${sep} ]]; then
+        compadd "$group[@]" "$expl[@]" "$opts[@]" \
+                -p "${pref%${sep}*${sep}}${sep}" -S "$sep" \
+                -M "r:|${sep}=* r:|=* $matcher" - "${${pref%${sep}}##*${sep}}"
+
+      elif [[ "$pref" = *${sep}* ]]; then
+        compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" \
+                -p "${pref%${sep}*}${sep}" \
+                -M "r:|${sep}=* r:|=* $matcher" - "${pref##*${sep}}"
+      else
+        compadd "$group[@]" "$expl[@]" -S '' "$opts[@]" \
+                -M "r:|${sep}=* r:|=* $matcher" - "$pref"
+      fi
+    fi
+    return
+  fi
+done
diff --git a/Completion/Unix/Command/_tar b/Completion/Unix/Command/_tar
new file mode 100644
index 000000000..3e3b3fc51
--- /dev/null
+++ b/Completion/Unix/Command/_tar
@@ -0,0 +1,171 @@
+#compdef tar gtar star
+
+# Tar completion.  Features:
+#  - Tries to collect tar commands from second position, single letter
+#    option, and long options.
+#  - `tar' can be called anything, will use the correct name
+#  - Uses the function `_tar_archive' to complete archive files.
+#  - Tries to find out if compressed archives should be used.
+#  - Completes files inside archive.  This is supposed to look pretty
+#    much as if the files are in an ordinary directory hierarchy.
+#    Handles extraction from compressed archives (GNU tar).
+#  - Anywhere -- appears, gets a list of long options to complete from
+#    tar itself (GNU tar)
+#  - Things like --directory=... are also completed correctly.
+
+local _tar_cmd tf tmp tmpb del index
+
+# First we collect in `_tar_cmd' single letter options describing what
+# should be done with the archive and if it is compressed. This
+# collected from options arguments that start with only one hyphen,
+# from some of the possible long options, and from the second word if
+# that does not start with a hyphen.
+
+tmp=("${(@M)words:#-[^-]*}")
+_tar_cmd="${(j::)tmp#-}"
+
+(( $words[(I)--(un|)gzip] ))     && _tar_cmd="z$_tar_cmd"
+(( $words[(I)--(un|)compress] )) && _tar_cmd="Z$_tar_cmd"
+(( $words[(I)--list] ))          && _tar_cmd="t$_tar_cmd"
+(( $words[(I)--(extract|get)] )) && _tar_cmd="x$_tar_cmd"
+(( $words[(I)--create] ))        && _tar_cmd="c$_tar_cmd"
+
+# Other ways of finding out what we're doing:  first
+# look in the first argument if it's not an option
+if [[ "$words[2]" = *[txcdruA]*~-* ]]; then
+  _tar_cmd="$words[2]$_tar_cmd"
+elif [[ $_tar_cmd != *[txcdruA]* && CURRENT -gt 2 ]]; then
+  # look for more obscure long options: these aren't all handled.
+  (( $words[(I)--(diff|compare)] )) && _tar_cmd="d$_tar_cmd"
+  (( $words[(I)--append] ))         && _tar_cmd="r$_tar_cmd"
+  (( $words[(I)--update] ))         && _tar_cmd="u$_tar_cmd"
+  (( $words[(I)--(con|)catenate] )) && _tar_cmd="A$_tar_cmd"
+  (( $words[(I)--delete] ))         && del=1
+fi
+
+# Next, we try to find the archive name and store it in `tf'. The name 
+# is searched after a `--file=' long option, in the third word if the
+# second one didn't start with a hyphen but contained a `f', and after 
+# an option argument starting with only one hyphen and containing a `f'.
+# unless that option argument also contains a `C'.
+
+tmp="$words[(I)--file=*]"
+tmpb="$words[(I)-*Cf*~--*]"
+
+if (( tmp )); then
+  tf=${~words[tmp][8,-1]}
+  _tar_cmd="f$_tar_cmd"
+elif [[ "$words[2]" != -* && "$words[2]" = *f* ]]; then
+  tf=${~words[3]}
+  _tar_cmd="f$_tar_cmd"
+elif (( tmpb )); then
+  tf=${~words[tmpb+2]}
+  wdir=${~words[tmpb+1]}
+  _tar_cmd="Cf$_tar_cmd"
+else
+  tmp="${words[(I)-*f*~--*]}"
+  if (( tmp )); then
+    tf=${~words[tmp+1]}
+    _tar_cmd="f$_tar_cmd"
+  fi
+fi
+
+# See if we should use a path prefix.  We have to use eval as the dir can
+# be any unevaluated thing which appears on the command line, including a
+# parameter.
+
+# This isn't used right now.
+
+tmp=${words[(r)--dir[a-z]#=*]}
+
+if [[ -n $tmp ]]; then
+  eval "wdir=(${tmp#*=})"
+fi
+
+# Now we complete...
+
+if [[ "$PREFIX" = --* ]]; then
+
+  # ...long options after `--'.
+
+  _arguments -- '--owner*:user:_users' \
+                 '*=(PROG|COMMAND)*:program:_command_names -e' \
+		 '*=ARCHIVE*:archive: _tar_archive' \
+		 '*=NAME*:file:_files' \
+		 '*=DIR*:directory:_files -/' \
+		 '*=CONTROL*::version control:(t numbered nil existing never simple)'
+
+elif [[ ( CURRENT -gt 2 && "$words[CURRENT-1]" = -[^C]#f* &&
+          "$words[CURRENT-1]" != --* ) ||
+        ( CURRENT -eq 3 && "$words[2]" = [^C]#f* && "$words[2]" != -* ) ||
+        ( CURRENT -gt 2 && "$words[CURRENT-2]" = -*C*f* &&
+          "$words[CURRENT-2]" != --* && "$words[CURRENT-1]" != --* ) ||
+        ( CURRENT -eq 4 && "$words[2]" = *C*f* && "$words[2]" != -* ) ]]; then
+
+  # ...archive files if we think they are wanted here.
+
+  _tar_archive
+
+elif [[ ( CURRENT -gt 2 && "$words[CURRENT-1]" = -[^f]#C*) ||
+        ( CURRENT -eq 3 && "$words[2]" = [^f]#C* ) ]]; then
+
+  # a directory for -C
+
+  _directories
+
+elif [[ ( "$_tar_cmd" = *[xt]* || -n $del ) && -n "$tf" ]]; then
+
+  # ...and files from the archive if we found an archive name and tar
+  # commands. We run `tar t...' on the file, keeping the list of
+  # filenames cached, plus the name of the tarfile so we know if it
+  # changes.  We skip this test if the alleged archive is not a file.
+
+  local largs=-tf expl
+
+  if [[ $_tar_cmd = *z* ]]; then
+    largs=-tzf
+  elif [[ $_tar_cmd = *j* ]]; then
+    largs=-tjf
+  elif [[ $_tar_cmd = *y* ]]; then
+    largs=-tyf
+  elif [[ $_tar_cmd = *Z* ]]; then
+    largs=-tZf
+  elif [[ $_tar_cmd = *I* ]]; then
+    largs=-tIf
+  else
+    # Some random compression program
+    tmp="${words[(r)--use-comp*]}"
+    [[ -n $tmp ]] && largs=($tmp -tf)
+  fi
+
+  if [[ $tf != $_tar_cache_name && -f $tf ]]; then
+    _tar_cache_list=("${(@f)$($words[1] $largs $tf)}")
+    _tar_cache_name=$tf
+  fi
+
+  _wanted files expl 'file from archive' _multi_parts / _tar_cache_list
+elif (( CURRENT == 2 )); then
+  _values -s '' 'tar function' \
+    '(c t u x)A[append to an archive]' \
+    '(A t u x)c[create a new archive]' \
+    '(A c u x)t[list archive contents]' \
+    '(A c t x)u[update archive]' \
+    '(A c t u)x[extract files from an archive]' \
+    'v[verbose output]' \
+    'f[specify archive file or device]'
+else
+  if ! (( index=$words[(I)-*C*] )); then
+    if [[ $words[2] = [^f]#C* ]]; then
+      index=1
+    elif [[ $words[2] = *f*C* ]]; then
+      index=2
+    fi
+  fi
+  if (( index )); then
+    index="$~words[index+1]"
+    [[ $index = (.|..|)/* ]] || index=~+/$index
+    _files -W $index
+  else
+    _files
+  fi
+fi
diff --git a/Completion/Unix/Type/_tar_archive b/Completion/Unix/Type/_tar_archive
new file mode 100644
index 000000000..c5ab0e9fc
--- /dev/null
+++ b/Completion/Unix/Type/_tar_archive
@@ -0,0 +1,26 @@
+#autoload
+
+# This is used to generate filenames usable as a tar archive. This may
+# get one argument, a collection of tar option characters that may be
+# used to find out what kind of filename is needed. If no argument is
+# given but the parameter `_tar_cmd' is set, that is used.
+# If your version of `tar' supports this you may want to complete
+# things like `host:file' or `user@host:file' here.
+
+local expl
+
+[[ $# -eq 0 && $+_tar_cmd -ne 0 ]] && set "$_tar_cmd"
+
+_description files expl 'archive file'
+
+if [[ "$1" = *[urtx]* ]]; then
+  if [[ "$1" = *[zZ]* ]]; then
+    _files "$expl[@]" -g '*.((tar|TAR).(gz|GZ|Z)|tgz)'
+  elif [[ "$1" = *[Ijy]* ]]; then
+    _files "$expl[@]" -g '*.(tar|TAR).bz2'
+  else
+    _files "$expl[@]" -g '*.(tar|TAR)'
+  fi
+else
+  _files "$expl[@]"
+fi