about summary refs log tree commit diff
path: root/Completion/Base/_long_options
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Base/_long_options')
-rw-r--r--Completion/Base/_long_options309
1 files changed, 309 insertions, 0 deletions
diff --git a/Completion/Base/_long_options b/Completion/Base/_long_options
new file mode 100644
index 000000000..a5d92632c
--- /dev/null
+++ b/Completion/Base/_long_options
@@ -0,0 +1,309 @@
+#autoload
+
+# This function tries to automatically complete long option names. For 
+# this it invokes the command from the line with the `--help' option
+# and then parses the output to find possible option names. For
+# options that get an argument after a `=', the function also tries to 
+# automatically find out what should be complete as the argument.
+# The possible completions for option-arguments can be described with
+# the arguments to this function. This is done by giving pairs of
+# patterns and actions as consecutive arguments. The actions specify
+# what should be done to complete arguemts of those options that match 
+# the pattern. The action may be a list of words in brackets or in
+# parentheses, separated by spaces. A list in brackets denotes
+# possible values for an optional argument, a list in parentheses
+# gives words to complete for mandatory arguments. If the action does
+# not start with a bracket or parentheses, it should be the name of a
+# command (probably with arguments) that should be invoked to complete 
+# after the equal sign. E.g.:
+#
+#  _long_options '*\*'     '(yes no)' \
+#                '*=FILE*' '_files' \
+#                '*=DIR*'  '_files -/'
+#
+# This makes `yes' and `no' be completed as the argument of options
+# whose description ends in a star, file names for options that
+# contain the substring `=FILE' in the description, and paths for
+# options whose description contains `=DIR'. Note the last two
+# patterns are not needed since this function always completes files
+# for option descriptions containing `=FILE' and paths for option
+# descriptions that contain `=DIR' or `=PATH'. These builtin patterns
+# can be overridden by patterns given as arguments, though.
+#
+# This function also accepts the `-X', `-J', and `-V' options which
+# are given to `compadd'. Finally, it accepts the option `-t'. If this 
+# is given, completion is only done on words starting with two hyphens.
+
+local opt expl group test i name action ret=1 tmp suffix
+
+setopt extendedglob
+
+# Get the options.
+
+group=()
+expl=()
+if [[ $1 = -*~--* ]]; then
+  while getopts "J:V:X:t" opt; do
+    case "$opt" in
+      [JV]) group=("-$opt" "$OPTARG");;
+      X)    expl=(-X "$OPTARG");;
+      t)    test=yes;;
+    esac
+  done
+  shift OPTIND-1
+fi
+
+# Test if we are completing after `--' if we were asked to do so.
+
+[[ -n "$test" && "$PREFIX" != --* ]] && return 1
+
+# We cache the information about options and the command name, see if
+# we can use the cache.
+
+if [[ "$words[1]" = (.|..)/* ]]; then
+  tmp="$PWD/$words[1]"
+else
+  tmp="$words[1]"
+fi
+
+if [[ "$tmp" != $_lo_cache_cmd ]]; then
+
+  # No, store the new command name and clear the old parameters.
+
+  _lo_cache_cmd="$tmp"
+  (( $+_lo_cache_actions )) && unset "$_lo_cache_names[@]" _lo_cache_actions _lo_cache_names
+
+  local opts pattern anum=1 tmpo str
+
+  # Now get the long option names by calling the command with `--help'.
+  # The parameter expansion trickery first gets the lines as separate
+  # array elements. Then we select all lines whose first non-blank
+  # character is a hyphen. Since some commands document more than one
+  # option per line, separated by commas, we convert commas int
+  # newlines and then split the result again at newlines after joining 
+  # the old array elements with newlines between them. Then we select
+  # those elements that start with two hyphens, remove anything up to
+  # those hyphens and anything from the space or comma after the
+  # option up to the end. Finally all elements with option strings
+  # that contain uppercase letters are removed.
+
+  opts=("--${(@)^${(@)${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$("$words[1]" --help)}:#[ 	]#-*}//,/
+}}:#[ 	]#--*}#*--}%%[, ]*}:#(*-[A-Z]*|)}")
+
+  # The interpretation of the options is completely table driven. We
+  # use the positional parameters we were given and a few standard
+  # ones. Then we loop through this table.
+
+  set -- "$@" '*=FILE*' '_files' '*=(DIR|PATH)*' '_files -/' '*' ''
+
+  while [[ $# -gt 1 ]]; do
+
+    # First, we get the pattern and the action to use and take them
+    # from the positional parameters.
+
+    pattern="$1"
+    action="$2"
+    shift 2
+
+    # We get all options matching the pattern and take them from the
+    # list we have built. If no option matches the pattern, we
+    # continue with the next.
+
+    tmp=("${(@M)opts:##$~pattern}")
+    opts=("${(@)opts:##$~pattern}")
+
+    (( $#tmp )) || continue
+
+    # Now we collect the options for the pattern in an array. We also
+    # check if the options take an argument after a `=', and if this
+    # argument is optional. The name of the array built contains
+    # `_arg_' for mandatory arguments, `_optarg_' for optional
+    # arguments, and `_simple_' for options that don't get an
+    # argument. In `_lo_cache_names' we save the names of these
+    # arrays and in `_lo_cache_actions' the associated actions.
+
+    # If the action is a list of words in brackets, this denotes
+    # options that get an optional argument. If the action is a list
+    # of words in parentheses, the option has to get an argument.
+    # In both cases we just build the array name to use.
+
+    if [[ "$action[1]" = '[' ]]; then
+      name="_lo_cache_optarg_$anum"
+    elif [[ "$action[1]" = '(' ]]; then
+      name="_lo_cache_arg_$anum"
+    else
+
+      # If there are option strings with a `[=', we take make these
+      # get an optional argument...
+
+      tmpo=("${(@M)tmp:#*\[\=*}")
+      if (( $#tmpo )); then
+
+        # ...by removing them from the option list and storing them in 
+	# an array.
+
+        tmp=("${(@)tmp:#*\[\=*}")
+        tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
+        _lo_cache_names[anum]="_lo_cache_optarg_$anum"
+        _lo_cache_actions[anum]="$action"
+        eval "_lo_cache_optarg_${anum}=(\"\$tmpo[@]\")"
+	(( anum++ ))
+      fi
+
+      # Now we do the same for option strings containing `=', these
+      # are options getting an argument.
+
+      tmpo=("${(@M)tmp:#*\=*}")
+      if (( $#tmpo )); then
+        tmp=("${(@)tmp:#*\=*}")
+        tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
+        _lo_cache_names[anum]="_lo_cache_arg_$anum"
+        _lo_cache_actions[anum]="$action"
+        eval "_lo_cache_arg_${anum}=(\"\$tmpo[@]\")"
+	(( anum++ ))
+      fi
+
+      # The name for the options without arguments, if any.
+
+      name="_lo_cache_simple_$anum"
+    fi
+    # Now filter out any option strings we don't like and stuff them
+    # in an array, if there are still some.
+
+    tmp=("${(@)${(@)tmp%%\=*}//[^a-z0-9-]}")
+    if (( $#tmp )); then
+      _lo_cache_names[anum]="$name"
+      _lo_cache_actions[anum]="$action"
+      eval "${name}=(\"\$tmp[@]\")"
+      (( anum++ ))
+    fi
+  done
+fi
+
+# We get the string from the line and and see if it already contains a 
+# equal sign.
+
+str="$PREFIX$SUFFIX"
+
+if [[ "$str" = *\=* ]]; then
+
+  # It contains a `=', now we ignore anything up to it, but first save 
+  # the old contents of the special parameters we change.
+
+  local oipre opre osuf pre parto parta pat patflags anum=1
+
+  oipre="$IPREFIX"
+  opre="$PREFIX"
+  osuf="$SUFFIX"
+
+  pre="${str%%\=*}"
+  IPREFIX="${IPREFIX}${pre}="
+  PREFIX="${str#*\=}"
+  SUFFIX=""
+
+  # We will check if the arrays contain an option matching what's on
+  # the line. To do this good, we build a pattern.
+
+  [[ -n "$_comp_correct" && $#pre -le _comp_correct ]] && return 1
+
+  pat="${pre}*"
+  patflags=''
+  _match_pattern _long_options pat patflags
+  [[ -n "$_comp_correct" ]] && patflags="$patflags(#a$_comp_correct)"
+
+  # Then we walk through the array names. For each array we test if it 
+  # contains the option string. If so, we `invoke' the action stored
+  # with the name. If the action is a list of words, we just add them, 
+  # otherwise we invoke the command or function named.
+
+  for name in "$_lo_cache_names[@]"; do
+    action="$_lo_cache_actions[anum]"
+    if (( ${(@)${(@P)name}[(I)$pre]} )); then
+      if [[ "$action[1]" = (\[|\() ]]; then
+        compadd - ${=action[2,-2]}
+      elif (( $#action )); then
+        $=action
+      fi
+
+      # We found the option string, return.
+
+      return
+    fi
+
+    # The array did not contain the full option string, see if it
+    # contains a string matching the string from the line.
+    # If there is one, we store the option string in `parto' and the
+    # element from `_lo_actions' in `parta'. If we find more than one
+    # such option or if we already had one, we set `parto' to `-'.
+
+    tmp=("${(@M)${(@P)name}:#${~pat}}")
+    if [[ $#tmp -eq 1 ]]; then
+      if [[ -z "$parto" ]]; then
+        parto="$tmp[1]"
+	parta="$action"
+      else
+        parto=-
+      fi
+    elif (( $#tmp )); then
+      parto=-
+    fi
+    (( anum++ ))
+  done
+
+  # If we found only one matching option, we accept it and immediatly
+  # try to complete the string after the `='.
+
+  if [[ -n "$parto" && "$parto" != - ]]; then
+    IPREFIX="${parto}="
+
+    if (( $#parta )); then
+      if [[ "$parta[1]" = (\[|\() ]]; then
+        compadd - ${=parta[2,-2]}
+      else
+        $=parta
+      fi
+    else
+      compadd -S '' - "$PREFIX"
+    fi
+    return
+  fi
+
+  # The option string was not found, restore the special parameters.
+
+  IPREFIX="$oipre"
+  PREFIX="$opre"
+  SUFFIX="$osuf"
+fi
+
+# The string on the line did not contain a `=', or we couldn't
+# complete the option string since there were more than one matching
+# what's on the line. So we just ad the option string as possible
+# matches, giving the string from the `=' on as a suffix.
+
+if [[ "$str" = *\=* ]]; then
+  str="=${str#*\=}"
+  PREFIX="${PREFIX%%\=*}"
+  suffix=()
+else
+  str=""
+  suffix=('-S=')
+fi
+
+anum=1
+for name in "$_lo_cache_names[@]"; do
+  action="$_lo_cache_actions[anum]"
+
+  if [[ "$name" = *_optarg_* ]]; then
+    compadd -M 'r:|-=* r:|=*' -Qq "$suffix[@]" -s "$str" - \
+            "${(@P)name}" && ret=0
+  elif [[ "$name" = *_arg_* ]]; then
+    compadd -M 'r:|-=* r:|=*' -Q "$suffix[@]" -s "$str" - \
+            "${(@P)name}" && ret=0
+  elif [[ -z "$str" ]]; then
+    compadd -M 'r:|-=* r:|=*' -Q - \
+            "${(@P)name}" && ret=0
+  fi
+  (( anum++ ))
+done
+
+return ret