about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Completion/Base/_arguments88
-rw-r--r--Completion/Base/_long_options8
-rw-r--r--Doc/Zsh/compsys.yo23
3 files changed, 97 insertions, 22 deletions
diff --git a/Completion/Base/_arguments b/Completion/Base/_arguments
index 86cd1c498..d51e6d0af 100644
--- a/Completion/Base/_arguments
+++ b/Completion/Base/_arguments
@@ -7,6 +7,7 @@ setopt localoptions extendedglob
 
 local long args rest ws cur nth def nm expl descr action opt arg tmp
 local single uns ret=1 soptseq soptseq1 sopts prefix line
+local beg optbeg argbeg
 
 # Associative arrays used to collect information about the options.
 
@@ -122,7 +123,10 @@ fi
 ws=( "${(@)words[2,-1]}" )
 cur=$(( CURRENT-2 ))
 nth=1
-liine=( "$words[1]" )
+line=( "$words[1]" )
+beg=2
+argbeg=2
+optbeg=2
 
 # ...until the current word is reached.
 
@@ -138,15 +142,27 @@ while [[ cur -gt 0 ]]; do
   fi
   arg=''
 
+  # See if we are after an option getting n arguments ended by something
+  # that matches the current word.
+
+  if [[ "$def" = \**[^\\]:* && "$ws[1]" = ${~${(M)def#*[^\\]:}[2,-2]} ]]; then
+    def=''
+    shift 1 ws
+    (( cur-- ))
+    (( beg++ ))
+    continue
+  fi
+
   # Remove one description/action pair from `def' if that isn't empty.
 
-  if [[ -n "$def" ]]; then
-    if [[ "$def" = ?*:*:* ]]; then
-      def="${def#?*:*:}"
+  if [[ -n "$def" && "$def" != \** ]]; then
+    if [[ "$def" = ?*[^\\]:*[^\\]:* ]]; then
+      def="${def#?*[^\\]:*[^\\]:}"
+      argbeg="$beg"
     else
       def=''
     fi
-  else
+  elif [[ -z "$def" ]]; then
 
     # If it is empty, and the word starts with `--' and we should
     # complete long options, just ignore this word, otherwise make sure
@@ -179,6 +195,8 @@ while [[ cur -gt 0 ]]; do
 	tmp="${ws[1][1]}${ws[1][-1]}"
 	if (( $+opts[$tmp] )); then
 	  def="$opts[$tmp]"
+	  optbeg="$beg"
+	  argbeg="$beg"
 	  uns="${ws[1][2,-1]}"
 	  opt=''
 	fi
@@ -217,9 +235,11 @@ while [[ cur -gt 0 ]]; do
 
 	  opt=''
 	  def="$dopts[$tmp[1]]"
+	  optbeg="$beg"
+	  argbeg="$beg"
 	  [[ -n "$oneshot[$tmp[1]]" ]] && unset "dopts[$tmp[1]]"
-	  if [[ "$def" = ?*:*:* ]]; then
-            def="${def#?*:*:}"
+	  if [[ "$def" = [^*]*[^\\]:*[^\\]:* ]]; then
+            def="${def#?*[^\\]:*[^\\]:}"
           else
             def=''
 	  fi
@@ -242,6 +262,8 @@ while [[ cur -gt 0 ]]; do
 	if (( $#tmp )); then
 	  opt=''
 	  def="$odopts[$tmp[1]]"
+	  optbeg="$beg"
+	  argbeg="$beg"
 	  [[ -n "$oneshot[$tmp[1]]" ]] && unset "odopts[$tmp[1]]"
 
 	  # For options whose first argument *may* come after the
@@ -251,8 +273,10 @@ while [[ cur -gt 0 ]]; do
 	  if [[ ( -z "$sopts" && "$ws[1]" != "$tmp[1]" ) ||
                 ( -n "$sopts" && ( ( $tmp[1] = [-+]? && "$ws[1]" != "${tmp[1][1]}"${~soptseq}"${tmp[1][2]}" ) ||
 		  		   ( $tmp[1] != [-+]? && "$ws[1]" != "$tmp[1]" ) ) ) ]]; then
-	    if [[ "$def" = ?*:*:* ]]; then
-              def="${def#?*:*:}"
+	    if [[ "$def" = [^*]*[^\\]:*[^\\]:* ]]; then
+              def="${def#?*[^\\]:*[^\\]:}"
+	      optbeg="$beg"
+	      argbeg="$beg"
             else
               def=''
             fi
@@ -284,6 +308,7 @@ while [[ cur -gt 0 ]]; do
 
   shift 1 ws
   (( cur-- ))
+  (( beg++ ))
 done
 
 # Now generate the matches.
@@ -313,10 +338,16 @@ else
 
       def="$args[nth]"
       [[ -z "$def" ]] && def="$rest"
+
+      if [[ "$def" = \** ]]; then
+        def="${def#*[^\\]:}"
+	[[ "$def" = :* ]] && def="$def[2,-1]"
+	[[ "$def" = :* ]] && def="$def[2,-1]"
+      fi
     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
+    # be in a string that starts with an option name and continues with
     # the first argument, test that (again, two loops).
 
     opt=yes
@@ -407,14 +438,41 @@ else
 
   if [[ -n "$def" ]]; then
 
-    # Ignore the leading colon describing optional arguments.
+    # Ignore the leading colon or `*...' describing optional arguments.
 
-    [[ "$def" = :* ]] && def="$def[2,-1]"
+    if [[ "$def" = :* ]]; then
+      def="$def[2,-1]"
+    elif [[ "$def" = \** ]]; then
+      tmp="${${(M)def#*[^\\]:}[2,-2]}"
+      def="${def#*[^\\]:}"
+
+      if [[ "$def" = :* ]]; then
+        if [[ "$def" = ::* ]]; then
+          def="$def[3,-1]"
+	  beg=$argbeg
+	else
+	  def="$def[2,-1]"
+	  beg=$optbeg
+	fi
+
+	shift beg words
+	(( CURRENT -= beg ))
+
+	if [[ -n "$tmp" ]]; then
+          tmp="$words[(ib:CURRENT:)${~tmp}]"
+	  [[ tmp -le $#words ]] && words=( "${(@)words[1,tmp-1]}" )
+	fi
+      fi
+    fi
 
     # Get the description and the action.
 
-    descr="${def%%:*}"
-    action="${${def#*:}%%:*}"
+    descr="${${${(M)def#*[^\\]:}[1,-2]}//\\\\:/:}"
+    if [[ "$def" = *[^\\]:*[^\\]:* ]]; then
+      action="${${${(M)${def#*[^\\]:}#*[^\\]:}[1,-2]}//\\\\:/:}"
+    else
+      action="${${def#*[^\\]:}//\\\\:/:}"
+    fi
 
     _description expl "$descr"
 
@@ -423,7 +481,7 @@ else
       # An empty action means that we should just display a message.
       _message "$descr"
       return ret
-    elif [[ "$action[1]" = \(*\) ]]; then
+    elif [[ "$action" = \(*\) ]]; then
 
       # Anything inside `(...)' is added directly.
 
diff --git a/Completion/Base/_long_options b/Completion/Base/_long_options
index 716ff8884..f0aa2eaff 100644
--- a/Completion/Base/_long_options
+++ b/Completion/Base/_long_options
@@ -141,9 +141,9 @@ if [[ "$tmp" != $_lo_cache_cmd ]]; then
     # First, we get the pattern and the action to use and take them
     # from the positional parameters.
 
-    pattern="${1%%:*}"
-    descr="${${1#*:}%%:*}"
-    action="${1#*:*:}"
+    pattern="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}"
+    descr="${${${(M)${1#*[^\\]:}#*[^\\]:}[1,-2]}//\\\\:/:}"
+    action="${${1#*[^\\]:*[^\\]:}//\\\\:/:}"
     shift
 
     # We get all options matching the pattern and take them from the
@@ -257,7 +257,7 @@ if [[ "$str" = *\=* ]]; then
 
       _description expl "$descr"
 
-      if [[ "$action[1]" = (\[*\]|\(*\)) ]]; then
+      if [[ "$action" = (\[*\]|\(*\)) ]]; then
         compadd "$expl[@]" - ${=action[2,-2]}
       elif [[ "$action" = \{*\} ]]; then
         eval "$action[2,-2]"
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 1181aa571..dbd1823cf 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -836,11 +836,13 @@ For options that get an argument after a `tt(=)', the function also tries
 to automatically find out what should be completed as the argument.
 The possible completions for option-arguments can be described with
 the arguments to this function. Each argument contains one description
-of the form <pattern>:<message>:<action>. The message will be printed 
+of the form `tt(<pattern>:<message>:<action>)'. The message will be printed 
 above the possible completion if the `description_format' configuration
 key is set (see above). The actions specify what
 should be done to complete arguments of those options that match 
-the pattern. The action may be a list of words in brackets or in
+the pattern. In both the message and the action a colon can be
+included by preceding it with a backslash. 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
@@ -910,6 +912,18 @@ var(description) has to be of the form
 `tt(:)var(message)tt(:)var(action)' or
 `tt(::)var(message)tt(:)var(action)', where the second form describes
 an optional argument and the first one describes a mandatory argument.
+The last description may also be of the form
+`tt(:*:)var(message)tt(:)var(action)' or
+`tt(:*)var(pattern)tt(:)var(message)tt(:)var(action)'. These describe
+multiple arguments. In the first form all following words on the line
+are to be completed as described by the var(action), in the second
+form all words up to a word matching the given var(pattern) are to be
+completed using the var(action). The `tt(*)' or the var(pattern) may
+also be separated from the var(message) by two or three colons. With
+two colons the tt(words) special array and the tt(CURRENT) special
+parameter are modified to refer only to the words after the option
+(with two colons) or to the words covered by this description (with
+three colons) during the execution or evaluation of the var(action).
 
 In the simplest form the var(opt-spec) is just the option name
 beginning with a minus or a plus sign, such as `tt(-foo)'. In this
@@ -941,9 +955,12 @@ tt(compgen) builtins and which make sure that the var(message) given
 in the description will be shown above the matches. During the
 evaluation or execution of the action the array `tt(line)' will be set 
 to the command name and normal arguments from the command line,
-i.e. to the words from the command line xcluding all options and their 
+i.e. to the words from the command line excluding all options and their 
 arguments.
 
+To include a colon in the var(message) or the var(action), it has to
+be preceded by a backslash.
+
 Normally the option names are taken as multi-character names and a
 word from the line is considered to contain only one option (or
 none). By giving the tt(-s) option to this function (as the first