about summary refs log tree commit diff
path: root/Completion/Base/_arguments
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Base/_arguments')
-rw-r--r--Completion/Base/_arguments388
1 files changed, 388 insertions, 0 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
new file mode 100644
index 000000000..5170acb84
--- /dev/null
+++ b/Completion/Base/_arguments
@@ -0,0 +1,388 @@
+#autoload
+
+# Complete the arguments of the current command according to the
+# descriptions given as arguments to this function.
+
+local long args rest ws cur nth def nm expl descr action opt arg tmp
+
+# Associative arrays used to collect information about the options.
+
+typeset -A opts mopts dopts dmopts odopts odmopts
+
+# See if we support long options, too.
+
+nth=$argv[(I)--]
+if (( nth )); then
+  long=( "${(@)argv[nth+1,-1]}" )
+  argv=("${(@)argv[1,nth-1]}")
+else
+  long=()
+fi
+
+# Now parse the arguments...
+
+args=()
+nth=1
+while (( $# )); do
+
+  # This describes a one-shot option.
+
+  if [[ "$1" = [-+]* ]]; then
+    if [[ "$1" = *:* ]]; then
+
+      # If the option name ends in a `-', the first argument comes
+      # directly after the option, if it ends in a `+', the first
+      # argument *may* come directly after the option, otherwise it
+      # is in the next word.
+
+      if [[ "$1" = [^:]##-:* ]]; then
+        dopts[${${1%%:*}[1,-2]}]="${1#*:}"
+      elif [[ "$1" = [^:]##+:* ]]; then
+        odopts[${${1%%:*}[1,-2]}]="${1#*:}"
+      else
+        opts[${1%%:*}]="${1#*:}"
+      fi
+    else
+      opts[$1]=''
+    fi
+  elif [[ "$1" = \*[-+]* ]]; then
+
+    # The same for options that may appear more than once.
+
+    if [[ "$1" = *:* ]]; then
+      if [[ "$1" = [^:]##-:* ]]; then
+        dmopts[${${1[2,-1]%%:*}[1,-2]}]="${1#*:}"
+      elif [[ "$1" = [^:]##+:* ]]; then
+        odmopts[${${1[2,-1]%%:*}[1,-2]}]="${1#*:}"
+      else
+        mopts[${1[2,-1]%%:*}]="${1#*:}"
+      fi
+    else
+      mopts[${1[2,-1]}]=''
+    fi
+  elif [[ "$1" = \*:* ]]; then
+
+    # This is `*:...', describing `all other arguments'.
+
+    rest="${1[3,-1]}"
+  elif [[ "$1" = :* ]]; then
+
+    # This is `:...', describing `the next argument'.
+
+    args[nth++]="${1#*:}"
+  else
+
+    # And this is `n:...', describing the `n'th argument.
+
+    args[${1%%:*}]="${1#*:}"
+    nth=$(( ${1%%:*} + 1 ))
+  fi
+  shift
+done
+
+if [[ $#long -ne 0 && "$PREFIX" = --* ]]; then
+
+   # If the current words starts with `--' and we should use long
+   # options, just call...
+
+  _long_options "$long[@]"
+else
+
+  # Otherwise parse the command line...
+
+  ws=( "${(@)words[2,-1]}" )
+  cur=$(( CURRENT-2 ))
+  nth=1
+
+  # ...until the current word is reached.
+
+  while [[ cur -gt 0 ]]; do
+
+    # `def' holds the description for the option we are currently after.
+    # Check if the next argument for the option is optional.
+
+    if [[ "$def" = :* ]]; then
+      opt=yes
+    else
+      opt=''
+    fi
+    arg=''
+
+    # Remove one description/action pair from `def' if that isn't empty.
+
+    if [[ -n "$def" ]]; then
+      if [[ "$def" = ?*:*:* ]]; then
+        def="${def#?*:*:}"
+      else
+        def=''
+      fi
+    else
+
+      # If it is empty, and the word starts with `--' and we should
+      # complete long options, just ignore this word, otherwise make sure
+      # we test for options below and handle normal arguments.
+
+      if [[ $#long -eq 0 || "$ws[1]" != --* ]]; then
+        opt=yes
+	arg=yes
+      else
+        def=''
+      fi
+    fi
+
+    if [[ -n "$opt" ]]; then
+
+      # `opt' was set above if we have to test if the word is an option.
+      # We first test for the simple options -- those without arguments or
+      # those whose arguments have to be given as separate words.
+
+      if (( $+opts[$ws[1]] )); then
+
+        # Options that may only be given once are removed from the
+        # associative array so that we are not offered them again.
+
+        def="$opts[$ws[1]]"
+        unset "opts[$ws[1]]"
+      elif (( $+mopts[$ws[1]] )); then
+        def="$mopts[$ws[1]]"
+      else
+
+        # If the word is none of the simple options, test for those
+        # whose first argument has to or may come directly after the
+        # option. This is done in four loops looking very much alike.
+
+        if (( $#dopts )); then
+
+	  # First we get the option names.
+
+	  tmp=( "${(@k)dopts}" )
+
+	  # Then we loop over them and see if the current word begins
+	  # with one of the option names.
+
+	  while (( $#tmp )); do
+	    [[ "$ws[1]" = ${tmp[1]}* ]] && break
+	    shift 1 tmp
+	  done
+
+	  if (( $#tmp )); then
+
+	    # It does. So use the description for it, but only from
+	    # the second argument on, because we are searching the
+	    # description for the next command line argument.
+
+	    opt=''
+	    def="$dopts[$tmp[1]]"
+	    unset "dopts[$tmp[1]]"
+	    if [[ "$def" = ?*:*:* ]]; then
+              def="${def#?*:*:}"
+            else
+              def=''
+	    fi
+          fi
+        fi
+	if [[ -n "$opt" && $#dmopts -ne 0 ]]; then
+	  tmp=( "${(@k)dmopts}" )
+	  while (( $#tmp )); do
+	    [[ "$ws[1]" = ${tmp[1]}* ]] && break
+	    shift 1 tmp
+	  done
+
+	  if (( $#tmp )); then
+	    opt=''
+	    def="$dmopts[$tmp[1]]"
+	    if [[ "$def" = ?*:*:* ]]; then
+              def="${def#?*:*:}"
+            else
+              def=''
+            fi
+          fi
+	fi
+        if [[ -n "$opt" && $#odopts -ne 0 ]]; then
+	  tmp=( "${(@k)odopts}" )
+	  while (( $#tmp )); do
+	    [[ "$ws[1]" = ${tmp[1]}* ]] && break
+	    shift 1 tmp
+	  done
+
+	  if (( $#tmp )); then
+	    opt=''
+	    def="$odopts[$tmp[1]]"
+	    unset "odopts[$tmp[1]]"
+
+	    # For options whose first argument *may* come after the
+	    # option, we skip over the first description only if there
+	    # is something after the option name on the line.
+
+	    if [[ "$ws[1]" != "$tmp[1]" ]]; then
+	      if [[ "$def" = ?*:*:* ]]; then
+                def="${def#?*:*:}"
+              else
+                def=''
+              fi
+	    fi
+          fi
+        fi
+	if [[ -n "$opt" && $#odmopts -ne 0 ]]; then
+	  tmp=( "${(@k)odmopts}" )
+	  while (( $#tmp )); do
+	    [[ "$ws[1]" = ${tmp[1]}* ]] && break
+	    shift 1 tmp
+	  done
+
+	  if (( $#tmp )); then
+	    opt=''
+	    def="$odmopts[$tmp[1]]"
+	    if [[ "$ws[1]" != "$tmp[1]" ]]; then
+	      if [[ "$def" = ?*:*:* ]]; then
+                def="${def#?*:*:}"
+              else
+                def=''
+              fi
+            fi
+          fi
+	fi
+
+	# If we didn't find a matching option description and we were
+	# told to use normal argument descriptions, just increase
+	# our counter `nth'.
+
+        if [[ -n "$opt" && -n "$arg" ]]; then
+          def=''
+	  (( nth++ ))
+        fi
+      fi
+    fi
+
+    shift 1 ws
+    (( cur-- ))
+  done
+
+  # Now generate the matches.
+
+  nm="$compstate[nmatches]"
+
+  if [[ -z "$def" || "$def" = :* ]]; then
+
+    # We either don't have a description for an argument of an option
+    # or we have a description for a optional argument.
+
+    if [[ -z "$def" ]]; then
+
+      # If we have none at all, use the one for this argument position.
+
+      def="$args[nth]"
+      [[ -z "$def" ]] && def="$rest"
+    fi
+
+    # In any case, we have to complete option names here, but we may
+    # be in a string that starts with an option names and continues with
+    # the first argument, test that (again, four loops).
+
+    opt=yes
+    if (( $#dopts )); then
+
+      # Get the option names.
+
+      tmp=( "${(@k)dopts}" )
+      while (( $#tmp )); do
+        if compset -P "$tmp[1]"; then
+
+	  # The current string starts with the option name, so ignore
+	  # that and complete the rest of the string.
+
+	  def="$dopts[$tmp[1]]"
+	  opt=''
+	  break
+        fi
+	shift 1 tmp
+      done
+    fi
+    if [[ -n "$opt" && $#dmopts -ne 0 ]]; then
+      tmp=( "${(@k)dmopts}" )
+      while (( $#tmp )); do
+        if compset -P "$tmp[1]"; then
+	  def="$dmopts[$tmp[1]]"
+	  opt=''
+	  break
+        fi
+	shift 1 tmp
+      done
+    fi
+    if [[ -n "$opt" && $#odopts -ne 0 ]]; then
+      tmp=( "${(@k)odopts}" )
+      while (( $#tmp )); do
+        if compset -P "$tmp[1]"; then
+	  def="$odopts[$tmp[1]]"
+	  opt=''
+	  break
+        fi
+	shift 1 tmp
+      done
+    fi
+    if [[ -n "$opt" && $#odmopts -ne 0 ]]; then
+      tmp=( "${(@k)odmopts}" )
+      while (( $#tmp )); do
+        if compset -P "$tmp[1]"; then
+	  def="$odmopts[$tmp[1]]"
+	  opt=''
+	  break
+        fi
+	shift 1 tmp
+      done
+    fi
+    if [[ -n "$opt" ]]; then
+
+      # We aren't in an argument directly after a option name, so
+      # all option names are possible matches.
+
+      _description expl option
+      compadd "$expl[@]" - "${(@k)opts}" "${(@k)mopts}" \
+                           "${(@k)dopts}" "${(@k)dmopts}" \
+			   "${(@k)odopts}" "${(@k)odmopts}"
+    fi
+  fi
+
+  # Now add the matches from the description, if any.
+
+  if [[ -n "$def" ]]; then
+
+    # Ignore the leading colon describing optional arguments.
+
+    [[ "$def" = :* ]] && def="$def[2,-1]"
+
+    # Get the description and the action.
+
+    descr="${def%%:*}"
+    action="${${def#*:}%%:*}"
+
+    _description expl "$descr"
+
+    if [[ -z "$action" ]]; then
+
+      # An empty action means that we should just display a message.
+      _message "$descr"
+      return 1
+    elif [[ "$action[1]" = \( ]]; then
+
+      # Anything inside `(...)' is added directly.
+
+      compadd "$expl[@]" - ${=action[2,-2]}
+    elif [[ "$action" = \ * ]]; then
+
+      # If the action starts with a space, we just call it.
+
+      $=action
+    else
+
+      # Otherwise we call it with the description-arguments built above.
+
+      action=( $=action )
+      "$action[1]" "$expl[@]" "${(@)action[2,-1]}"
+    fi
+  fi
+
+  # Set the return value.
+
+  [[  nm -ne "$compstate[nmatches]" ]]
+fi