diff options
-rw-r--r-- | Completion/Base/_arguments | 88 | ||||
-rw-r--r-- | Completion/Base/_long_options | 8 | ||||
-rw-r--r-- | Doc/Zsh/compsys.yo | 23 |
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 |