1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-05-23 16:36:05 +02:00

44274: allow finer control of completion match soring with compadd's -o option

This commit is contained in:
Oliver Kiddle 2019-05-07 23:24:49 +02:00
parent 5200637bda
commit cd6fd2b0a3
24 changed files with 257 additions and 101 deletions

View File

@ -1,5 +1,21 @@
2019-05-07 Oliver Kiddle <okiddle@yahoo.co.uk> 2019-05-07 Oliver Kiddle <okiddle@yahoo.co.uk>
* 44274: Completion/Base/Core/_description,
Completion/Base/Utility/_describe, Completion/Base/Utility/_guard,
Completion/Base/Utility/_multi_parts,
Completion/Base/Utility/_sep_parts,
Completion/Base/Utility/_sequence, Completion/Zsh/Command/_compadd,
Completion/Darwin/Type/_mac_files_for_application,
Completion/Redhat/Command/_yum, Completion/Unix/Command/_git,
Completion/Unix/Type/_canonical_paths,
Completion/Unix/Type/_baudrates, Completion/Unix/Type/_files,
Completion/Unix/Type/_list_files, Completion/Unix/Type/_path_files,
Completion/Zsh/Type/_file_descriptors,
Doc/Zsh/compsys.yo, Doc/Zsh/compwid.yo, NEWS,
Src/Zle/comp.h, Src/Zle/compcore.c, Src/Zle/complete.c:
allow finer control of completion match soring with
arguments to compadd's -o option
* Gautam Iyer: gitlab !6: Completion/Unix/Command/_rclone: * Gautam Iyer: gitlab !6: Completion/Unix/Command/_rclone:
Rudimentary rclone completion Rudimentary rclone completion

View File

@ -1,13 +1,13 @@
#autoload #autoload
local name gropt nopt xopt format gname hidden hide match opts tag sort local name nopt xopt format gname hidden hide match opts tag
local -a gropt sort
opts=() opts=()
gropt=(-J)
xopt=(-X) xopt=(-X)
nopt=() nopt=()
zparseopts -K -D -a nopt 1 2 V=gropt J=gropt x=xopt zparseopts -K -D -a nopt 1 2 V=gropt J x=xopt
3="${${3##[[:blank:]]#}%%[[:blank:]]#}" 3="${${3##[[:blank:]]#}%%[[:blank:]]#}"
[[ -n "$3" ]] && _lastdescr=( "$_lastdescr[@]" "$3" ) [[ -n "$3" ]] && _lastdescr=( "$_lastdescr[@]" "$3" )
@ -33,14 +33,18 @@ zstyle -s ":completion:${curcontext}:$1" matcher match &&
# Use sort style, but ignore `menu' value to help _expand. # Use sort style, but ignore `menu' value to help _expand.
# Also don't override explicit use of -V. # Also don't override explicit use of -V.
if { zstyle -s ":completion:${curcontext}:$1" sort sort || if [[ -z "$gropt" ]]; then
zstyle -s ":completion:${curcontext}:" sort sort; } && if zstyle -a ":completion:${curcontext}:$1" sort sort ||
[[ "$gropt" = -J && $sort != menu ]]; then zstyle -a ":completion:${curcontext}:" sort sort
if [[ "$sort" = (yes|true|1|on) ]]; then then
gropt=(-J) if [[ -z "${(@)sort:#(match|numeric|reverse)}" ]]; then
else gropt=( -o ${(j.,.)sort} )
gropt=(-V) elif [[ "$sort" != (yes|true|1|on|menu) ]]; then
gropt=( -o nosort )
fi fi
fi
else
gropt=( -o nosort )
fi fi
if [[ -z "$_comp_no_ignore" ]]; then if [[ -z "$_comp_no_ignore" ]]; then
@ -79,15 +83,15 @@ fi
if [[ -n "$gname" ]]; then if [[ -n "$gname" ]]; then
if [[ -n "$format" ]]; then if [[ -n "$format" ]]; then
set -A "$name" "$opts[@]" "$nopt[@]" "$gropt" "$gname" "$xopt" "$format" set -A "$name" "$opts[@]" "$nopt[@]" "$gropt[@]" -J "$gname" "$xopt" "$format"
else else
set -A "$name" "$opts[@]" "$nopt[@]" "$gropt" "$gname" set -A "$name" "$opts[@]" "$nopt[@]" "$gropt[@]" -J "$gname"
fi fi
else else
if [[ -n "$format" ]]; then if [[ -n "$format" ]]; then
set -A "$name" "$opts[@]" "$nopt[@]" "$gropt" -default- "$xopt" "$format" set -A "$name" "$opts[@]" "$nopt[@]" "$gropt[@]" -J -default- "$xopt" "$format"
else else
set -A "$name" "$opts[@]" "$nopt[@]" "$gropt" -default- set -A "$name" "$opts[@]" "$nopt[@]" "$gropt[@]" -J -default-
fi fi
fi fi

View File

@ -108,10 +108,10 @@ while _tags; do
fi fi
if [[ -n $_mats ]]; then if [[ -n $_mats ]]; then
compadd "$_opts[@]" "${(@)_expl:/-J/-2V}" -D $_strs -O $_mats - \ compadd "$_opts[@]" -2 -o nosort "${_expl[@]}" -D $_strs -O $_mats - \
"${(@)${(@M)${(@P)_mats}##([^:\\]|\\?)##}//\\(#b)(?)/$match[1]}" "${(@)${(@M)${(@P)_mats}##([^:\\]|\\?)##}//\\(#b)(?)/$match[1]}"
else else
compadd "$_opts[@]" "${(@)_expl:/-J/-2V}" -D $_strs - \ compadd "$_opts[@]" -2 -o nosort "${_expl[@]}" -D $_strs - \
"${(@)${(@M)${(@P)_strs}##([^:\\]|\\?)##}//\\(#b)(?)/$match[1]}" "${(@)${(@M)${(@P)_strs}##([^:\\]|\\?)##}//\\(#b)(?)/$match[1]}"
fi fi
done done

View File

@ -2,7 +2,7 @@
local garbage local garbage
zparseopts -K -D -a garbage M: J: V: 1 2 n F: X: zparseopts -K -D -a garbage M+: J+: V+: 1 2 o+: n F: X+:
[[ "$PREFIX$SUFFIX" != $~1 ]] && return 1 [[ "$PREFIX$SUFFIX" != $~1 ]] && return 1

View File

@ -14,8 +14,8 @@ typeset -U tmp1 matches
# Get the options. # Get the options.
zparseopts -D -a sopts \ zparseopts -D -a sopts \
'J+:=group' 'V+:=group' 'X+:=expl' 'P:=opts' 'F:=opts' \ 'J+:=group' 'V+:=group' 'x+:=expl' 'X+:=expl' 'P:=opts' 'F:=opts' \
S: r: R: q 1 2 n f 'M+:=matcher' 'i=imm' S: r: R: q 1 2 o+: n f 'M+:=matcher' 'i=imm'
sopts=( "$sopts[@]" "$opts[@]" ) sopts=( "$sopts[@]" "$opts[@]" )
if (( $#matcher )); then if (( $#matcher )); then

View File

@ -22,8 +22,8 @@ local matchflags opt group expl nm=$compstate[nmatches] opre osuf opts matcher
# Get the options. # Get the options.
zparseopts -D -a opts \ zparseopts -D -a opts 'J+:=group' 'V+:=group' P: F: S: r: R: q 1 2 o+: n \
'J+:=group' 'V+:=group' P: F: S: r: R: q 1 2 n 'X+:=expl' 'M+:=matcher' 'x+:=expl' 'X+:=expl' 'M+:=matcher'
# Get the string from the line. # Get the string from the line.

View File

@ -10,7 +10,8 @@
local curcontext="$curcontext" nm="$compstate[nmatches]" pre qsep nosep minus local curcontext="$curcontext" nm="$compstate[nmatches]" pre qsep nosep minus
local -a sep num pref suf end uniq dedup local -a sep num pref suf end uniq dedup
zparseopts -D -a opts s:=sep n:=num p:=pref i:=pref P:=pref I:=suf S:=suf q=suf r:=suf R:=suf C:=cont d=uniq M: J: X: x: zparseopts -D -a opts s:=sep n:=num p:=pref i:=pref P:=pref I:=suf S:=suf \
q=suf r:=suf R:=suf C:=cont d=uniq M+: J+: V+: 1 2 o+: X+: x+:
(( $#cont )) && curcontext="${curcontext%:*}:$cont[2]" (( $#cont )) && curcontext="${curcontext%:*}:$cont[2]"
(( $#sep )) || sep[2]=, (( $#sep )) || sep[2]=,

View File

@ -35,7 +35,7 @@ _mac_parse_info_plist() {
# Try to complete files for the specified application. # Try to complete files for the specified application.
_mac_files_for_application() { _mac_files_for_application() {
local -a opts local -a opts
zparseopts -D -a opts q n 1 2 P: S: r: R: W: X+: M+: F: J+: V+: zparseopts -D -a opts q n 1 2 o+: P: S: r: R: W: x+: X+: M+: F: J+: V+:
local app_path local app_path
_retrieve_mac_apps _retrieve_mac_apps

View File

@ -212,7 +212,7 @@ _yum_ids() {
# `${(@)@[...]}' selects a subrange from $@ # `${(@)@[...]}' selects a subrange from $@
# `${(@)@[1,-2]}' are all except the last argument # `${(@)@[1,-2]}' are all except the last argument
# `$@[$#]' is the last argument, e.g. the first suggestable ID # `$@[$#]' is the last argument, e.g. the first suggestable ID
compadd "${(@)@[1,-2]:/-J/-V}" -M "B:0=" {$@[$#]..$maxid} compadd "${(@)@[1,-2]}" -o numeric -M "B:0=" {$@[$#]..$maxid}
} }
_yum_ranges() { _yum_ranges() {

View File

@ -5688,7 +5688,7 @@ __git_ignore_line () {
__git_ignore_line_inside_arguments () { __git_ignore_line_inside_arguments () {
declare -a compadd_opts declare -a compadd_opts
zparseopts -D -E -a compadd_opts V: J: 1 2 n f X: M: P: S: r: R: q F: zparseopts -D -E -a compadd_opts V+: J+: 1 2 o+: n f x+: X+: M+: P: S: r: R: q F:
__git_ignore_line $* $compadd_opts __git_ignore_line $* $compadd_opts
} }
@ -6160,7 +6160,7 @@ __git_ref_fields () {
local match mbegin mend local match mbegin mend
local -a cfields fields append opts all local -a cfields fields append opts all
zparseopts -D -E -a opts x: X: J: V: a=all zparseopts -D -E -a opts M+: x+: X+: J+: V+: o+: 1 2 a=all
if compset -P 1 '(#b)(*):'; then if compset -P 1 '(#b)(*):'; then
case $match[1] in case $match[1] in
@ -6731,7 +6731,7 @@ __git_tags_of_type () {
tags=(${${(M)${(f)"$(_call_program ${(q)type}-tag-refs "git for-each-ref --format='%(*objecttype)%(objecttype) %(refname)' refs/tags 2>/dev/null")"}:#$type(tag|) *}#$type(tag|) refs/tags/}) tags=(${${(M)${(f)"$(_call_program ${(q)type}-tag-refs "git for-each-ref --format='%(*objecttype)%(objecttype) %(refname)' refs/tags 2>/dev/null")"}:#$type(tag|) *}#$type(tag|) refs/tags/})
__git_command_successful $pipestatus || return 1 __git_command_successful $pipestatus || return 1
_wanted $type-tags expl "$type tag" compadd -M 'r:|/=* r:|=*' "$@" -a - tags _wanted $type-tags expl "$type tag" compadd -M 'r:|/=* r:|=*' "$@" -o numeric -a - tags
} }
# Reference Argument Types # Reference Argument Types
@ -6826,7 +6826,7 @@ __git_files_relative () {
__git_files () { __git_files () {
local compadd_opts opts tag description gitcdup gitprefix files expl local compadd_opts opts tag description gitcdup gitprefix files expl
zparseopts -D -E -a compadd_opts V: J: 1 2 n f X: M: P: S: r: R: q F: zparseopts -D -E -a compadd_opts V+: J+: 1 2 o+: n f x+: X+: M+: P: S: r: R: q F:
zparseopts -D -E -a opts -- -cached -deleted -modified -others -ignored -unmerged -killed x+: --exclude+: zparseopts -D -E -a opts -- -cached -deleted -modified -others -ignored -unmerged -killed x+: --exclude+:
tag=$1 description=$2; shift 2 tag=$1 description=$2; shift 2
@ -6957,7 +6957,7 @@ __git_tree_files () {
shift shift
fi fi
zparseopts -D -E -a compadd_opts V: J: 1 2 n f X: M: P: S: r: R: q F: zparseopts -D -E -a compadd_opts V+: J+: 1 2 o+: n f x+: X+: M+: P: S: r: R: q F:
[[ "$1" == */ ]] && Path="$1" || Path="${1:h}/" [[ "$1" == */ ]] && Path="$1" || Path="${1:h}/"
shift shift
@ -7037,7 +7037,7 @@ __git_any_repositories_or_references () {
__git_guard () { __git_guard () {
declare -A opts declare -A opts
zparseopts -K -D -A opts M: J: V: 1 2 n F: X: zparseopts -K -D -A opts M+: J+: V+: 1 2 o+: n F: x+: X+:
[[ "$PREFIX$SUFFIX" != $~1 ]] && return 1 [[ "$PREFIX$SUFFIX" != $~1 ]] && return 1
@ -7075,7 +7075,7 @@ __git_guard_diff-stat-width () {
__git_guard_number () { __git_guard_number () {
declare -A opts declare -A opts
zparseopts -K -D -A opts M: J: V: 1 2 n F: X: zparseopts -K -D -A opts M+: J+: V+: 1 2 o+: n F: x+: X+:
_guard '[[:digit:]]#' ${1:-number} _guard '[[:digit:]]#' ${1:-number}
} }

View File

@ -72,7 +72,6 @@ if (( ${+opts[-f]} )); then
done done
fi fi
# -1V removes dupes (which there shouldn't be) and otherwise leaves the # -1 removes dupes (which there shouldn't be)
# order in the $rates array intact. _description -1 -o numeric baud-rates expl 'baud rate'
_description -1V baud-rates expl 'baud rate' compadd "${argv[@]}" "$expl[@]" -- "${rates[@]}"
compadd "${(@)argv/#-J/-V}" "$expl[@]" -- "${rates[@]}"

View File

@ -5,13 +5,14 @@
# (relative path when an absolute path is given, and vice versa; when ..'s are # (relative path when an absolute path is given, and vice versa; when ..'s are
# present in the word to be completed, and some paths got from symlinks). # present in the word to be completed, and some paths got from symlinks).
# Usage: _canonical_paths [-A var] [-N] [-MJV12nfX] tag desc [paths...] # Usage: _canonical_paths [-A var] [-N] [-MJV12onfX] tag desc [paths...]
# -A, if specified, takes the paths from the array variable specified. Paths # -A, if specified, takes the paths from the array variable specified. Paths
# can also be specified on the command line as shown above. -N, if specified, # can also be specified on the command line as shown above. -N, if specified,
# prevents canonicalizing the paths given before using them for completion, in # prevents canonicalizing the paths given before using them for completion, in
# case they are already so. `tag' and `desc' arguments are well, obvious :) In # case they are already so. `tag' and `desc' arguments are well, obvious :) In
# addition, the options -M, -J, -V, -1, -2, -n, -F, -X are passed to compadd. # addition, the options -M, -J, -V, -1, -2, -o, -n, -F, -x, -X are passed to
# compadd.
_canonical_paths_add_paths () { _canonical_paths_add_paths () {
# origpref = original prefix # origpref = original prefix
@ -59,7 +60,7 @@ _canonical_paths() {
local __index local __index
typeset -a __gopts __opts typeset -a __gopts __opts
zparseopts -D -a __gopts M: J: V: 1 2 n F: X: A:=__opts N=__opts zparseopts -D -a __gopts M+: J+: V+: o+: 1 2 n F: x+: X+: A:=__opts N=__opts
: ${1:=canonical-paths} ${2:=path} : ${1:=canonical-paths} ${2:=path}

View File

@ -27,7 +27,7 @@ local opts tmp glob pat pats expl tag i def descr end ign tried
local type sdef ignvars ignvar prepath oprefix rfiles rfile local type sdef ignvars ignvar prepath oprefix rfiles rfile
zparseopts -a opts \ zparseopts -a opts \
'/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X+: M+: F: J+: V+: '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: x+: X+: M+: F: J+: V+: o+:
type="${(@j::M)${(@)tmp#-}#?}" type="${(@j::M)${(@)tmp#-}#?}"
if (( $tmp[(I)-g*] )); then if (( $tmp[(I)-g*] )); then

View File

@ -64,6 +64,6 @@ for f in ${(PQ)1}; do
${(r:8:)stat[gid]} ${(l:8:)stat[size]} $stat[mtime] $f") ${(r:8:)stat[gid]} ${(l:8:)stat[size]} $stat[mtime] $f")
done done
(( ${#listfiles} )) && listopts=(-d listfiles -l -o) (( ${#listfiles} )) && listopts=(-d listfiles -l -o match)
return 0 return 0

View File

@ -59,7 +59,7 @@ exppaths=()
zparseopts -a mopts \ zparseopts -a mopts \
'P:=pfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \ 'P:=pfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \
'W:=prepaths' 'F:=ignore' 'M+:=matcher' \ 'W:=prepaths' 'F:=ignore' 'M+:=matcher' \
J+: V+: X+: 1 2 n 'f=tmp1' '/=tmp1' 'g+:-=tmp1' J+: V+: x+: X+: 1 2 o+: n 'f=tmp1' '/=tmp1' 'g+:-=tmp1'
sopt="-${(@j::M)${(@)tmp1#-}#?}" sopt="-${(@j::M)${(@)tmp1#-}#?}"
(( $tmp1[(I)-[/g]*] )) && haspats=yes (( $tmp1[(I)-[/g]*] )) && haspats=yes
@ -168,7 +168,7 @@ if zstyle -s ":completion:${curcontext}:" file-sort tmp1; then
if [[ "$sort" = on ]]; then if [[ "$sort" = on ]]; then
sort= sort=
else else
mopts=( "${(@)mopts/#-J/-V}" ) mopts=( -o nosort "${mopts[@]}" )
tmp2=() tmp2=()
for tmp1 in "$pats[@]"; do for tmp1 in "$pats[@]"; do

View File

@ -14,9 +14,13 @@ _arguments -C -s -S -A "-*" \
'(-a)-k[matches are keys of specified associative arrays]' \ '(-a)-k[matches are keys of specified associative arrays]' \
'-d+[specify display strings]:array:_parameters -g "*array*"' \ '-d+[specify display strings]:array:_parameters -g "*array*"' \
'-l[list display strings one per line, not in columns]' \ '-l[list display strings one per line, not in columns]' \
'-o[order matches by match string not by display string]' \ '-o[specify order for matches by match string not by display string]:: : _values -s , order
'(-1 -E)-J+[specify match group which will be sorted]:group' \ "match[order by match not by display string]"
'-V+[specify pre-ordered match group]:group' \ "nosort[matches are pre-ordered]"
"numeric[order numerically]"
"reverse[order backwards]"' \
'(-1 -E)-J+[specify match group]:group' \
'!-V+:group' \
'(-J -E)-1[remove only consecutive duplicates from group]' \ '(-J -E)-1[remove only consecutive duplicates from group]' \
'-2[preserve all duplicates]' \ '-2[preserve all duplicates]' \
'(-x)-X[specify explanation]:explanation' \ '(-x)-X[specify explanation]:explanation' \
@ -45,7 +49,7 @@ if [[ -n $state ]]; then
elif (( $+opt_args[-k] )); then elif (( $+opt_args[-k] )); then
_parameters -g "*assoc*" && ret=0 _parameters -g "*assoc*" && ret=0
else else
_message -e candidate candidates _message -e candidates candidate
fi fi
fi fi

View File

@ -56,4 +56,4 @@ fi
fds=( 0 1 2 $fds ) fds=( 0 1 2 $fds )
_description -V file-descriptors expl 'file descriptor' _description -V file-descriptors expl 'file descriptor'
compadd $disp "${@/-J/-V}" "$expl[@]" -a fds compadd $disp -o nosort "$@" "$expl[@]" -a fds

View File

@ -2534,20 +2534,20 @@ is started, making it easy to select either of them.
) )
kindex(sort, completion style) kindex(sort, completion style)
item(tt(sort))( item(tt(sort))(
Many completion widgets call tt(_description) at some point which This allows the standard ordering of matches to be overridden.
decides whether the matches are added sorted or unsorted (often
indirectly via tt(_wanted) or tt(_requested)). This style can be set If its value is `tt(true)' or `tt(false)', sorting is enabled or disabled.
explicitly to one of the usual `true' or `false' values as an override. Additionally the values associated with the `tt(-o)' option to tt(compadd) can
If it is not set for the context, the standard behaviour of the also be listed: tt(match), tt(nosort), tt(numeric), tt(reverse). If it is not
calling widget is used. set for the context, the standard behaviour of the calling widget is used.
The style is tested first against the full context including the tag, and The style is tested first against the full context including the tag, and
if that fails to produce a value against the context without the tag. if that fails to produce a value against the context without the tag.
If the calling widget explicitly requests unsorted matches, this is usually In many cases where a calling widget explicitly selects a particular ordering
honoured. However, the default (unsorted) behaviour of completion in lieu of the default, a value of `tt(true)' is not honoured. An example of
for the command history may be overridden by setting the style to where this is not the case is for command history where the default of sorting
`true'. matches chronologically may be overridden by setting the style to `true'.
In the tt(_expand) completer, if it is set to In the tt(_expand) completer, if it is set to
`true', the expansions generated will always be sorted. If it is set `true', the expansions generated will always be sorted. If it is set
@ -4404,11 +4404,11 @@ convention is not enforced). The description for the corresponding set
of matches is passed to the function in var(descr). of matches is passed to the function in var(descr).
The styles tested are: tt(format), tt(hidden), tt(matcher), The styles tested are: tt(format), tt(hidden), tt(matcher),
tt(ignored-patterns) and tt(group-name). The tt(format) style is first tt(ignore-line), tt(ignored-patterns), tt(group-name) and tt(sort).
tested for the given var(tag) and then for the tt(descriptions) tag if The tt(format) style is first tested for the given var(tag) and then for
no value was found, while the remainder are only tested for the tag the tt(descriptions) tag if no value was found, while the remainder are
given as the first argument. The function also calls tt(_setup) only tested for the tag given as the first argument. The function also
which tests some more styles. calls tt(_setup) which tests some more styles.
The string returned by the tt(format) style (if any) will be modified so The string returned by the tt(format) style (if any) will be modified so
that the sequence `tt(%d)' is replaced by the var(descr) given as the third that the sequence `tt(%d)' is replaced by the var(descr) given as the third

View File

@ -446,12 +446,13 @@ startitem()
findex(compadd) findex(compadd)
cindex(completion widgets, adding specified matches) cindex(completion widgets, adding specified matches)
redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ ))ifnztexi( ))) redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ ))ifnztexi( )))
xitem(tt(compadd )[ tt(-akqQfenUlo12C) ] [ tt(-F) var(array) ]) xitem(tt(compadd )[ tt(-akqQfenUl12C) ] [ tt(-F) var(array) ])
xitem(SPACES()[tt(-P) var(prefix) ] [ tt(-S) var(suffix) ]) xitem(SPACES()[tt(-P) var(prefix) ] [ tt(-S) var(suffix) ])
xitem(SPACES()[tt(-p) var(hidden-prefix) ] [ tt(-s) var(hidden-suffix) ]) xitem(SPACES()[tt(-p) var(hidden-prefix) ] [ tt(-s) var(hidden-suffix) ])
xitem(SPACES()[tt(-i) var(ignored-prefix) ] [ tt(-I) var(ignored-suffix) ]) xitem(SPACES()[tt(-i) var(ignored-prefix) ] [ tt(-I) var(ignored-suffix) ])
xitem(SPACES()[tt(-W) var(file-prefix) ] [ tt(-d) var(array) ]) xitem(SPACES()[tt(-W) var(file-prefix) ] [ tt(-d) var(array) ])
xitem(SPACES()[tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ] [ tt(-x) var(message) ]) xitem(SPACES()[tt(-J) var(group-name) ] [ tt(-X) var(explanation) ] [ tt(-x) var(message) ])
xitem(SPACES()[tt(-V) var(group-name) ] [ tt(-o) [ var(order) ] ])
xitem(SPACES()[tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ]) xitem(SPACES()[tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ])
xitem(SPACES()[tt(-D) var(array) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ]) xitem(SPACES()[tt(-D) var(array) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ])
xitem(SPACES()[tt(-E) var(number) ]) xitem(SPACES()[tt(-E) var(number) ])
@ -540,18 +541,40 @@ This option only has an effect if used together with the tt(-d)
option. If it is given, the display strings are listed one per line, option. If it is given, the display strings are listed one per line,
not arrayed in columns. not arrayed in columns.
) )
item(tt(-o))( item(tt(-o) [ var(order) ])(
This option only has an effect if used together with the tt(-d) This controls the order in which matches are sorted. var(order) is a
option. If it is given, the order of the output is determined by the comma-separated list comprising the following possible values. These values
match strings; otherwise it is determined by the display strings can be abbreviated to their initial two or three characters. Note that the
(i.e. the strings given by the tt(-d) option). order forms part of the group name space so matches with different orderings
will not be in the same group.
startitem()
item(tt(match))(
If given, the order of the output is determined by the match strings;
otherwise it is determined by the display strings (i.e. the strings given
by the tt(-d) option). This is the default if `tt(-o)' is specified but
the var(order) argument is omitted.
) )
item(tt(-J) var(name))( item(tt(nosort))(
This specifies that the matches are pre-sorted and their order should be
preserved. This value only makes sense alone and cannot be combined with any
others.
)
item(tt(numeric))(
If the matches include numbers, sort them numerically rather than
lexicographically.
)
item(tt(reverse))(
Arrange the matches backwards by reversing the sort ordering.
)
enditem()
)
item(tt(-J) var(group-name))(
Gives the name of the group of matches the words should be stored in. Gives the name of the group of matches the words should be stored in.
) )
item(tt(-V) var(name))( item(tt(-V) var(group-name))(
Like tt(-J) but naming an unsorted group. These are in a different name Like tt(-J) but naming an unsorted group. This option is identical to
space than groups created with the tt(-J) flag. the combination of tt(-J) and tt(-o nosort).
) )
item(tt(-1))( item(tt(-1))(
If given together with the tt(-V) option, makes If given together with the tt(-V) option, makes

5
NEWS
View File

@ -21,6 +21,11 @@ functions may wish to familiarise themselves with `_normal -p` and
The option CD_SILENT was added to suppress all output from cd (whether The option CD_SILENT was added to suppress all output from cd (whether
explicit or implicit with AUTO_CD). It is disabled by default. explicit or implicit with AUTO_CD). It is disabled by default.
The compadd builtin's -o option now takes an optional argument to
specify the order of completion matches. This affects the display
of candidate matches and the order in which they are selected when
cycling between them using menu completion.
Changes from 5.6.2 to 5.7.1 Changes from 5.6.2 to 5.7.1
--------------------------- ---------------------------

View File

@ -90,6 +90,9 @@ struct cmgroup {
#define CGF_PACKED 32 /* LIST_PACKED for this group */ #define CGF_PACKED 32 /* LIST_PACKED for this group */
#define CGF_ROWS 64 /* LIST_ROWS_FIRST for this group */ #define CGF_ROWS 64 /* LIST_ROWS_FIRST for this group */
#define CGF_FILES 128 /* contains file names */ #define CGF_FILES 128 /* contains file names */
#define CGF_MATSORT 256 /* sort by match rather than by display string */
#define CGF_NUMSORT 512 /* sort numerically */
#define CGF_REVSORT 1024 /* sort in reverse */
/* This is the struct used to hold matches. */ /* This is the struct used to hold matches. */
@ -300,6 +303,9 @@ struct menuinfo {
#define CAF_ARRAYS 32 /* compadd -a or -k: array/assoc parameter names */ #define CAF_ARRAYS 32 /* compadd -a or -k: array/assoc parameter names */
#define CAF_KEYS 64 /* compadd -k: assoc parameter names */ #define CAF_KEYS 64 /* compadd -k: assoc parameter names */
#define CAF_ALL 128 /* compadd -C: _all_matches */ #define CAF_ALL 128 /* compadd -C: _all_matches */
#define CAF_MATSORT 256 /* compadd -o match: sort by match rather than by display string */
#define CAF_NUMSORT 512 /* compadd -o numeric: sort numerically */
#define CAF_REVSORT 1024 /* compadd -o numeric: sort in reverse */
/* Data for compadd and addmatches() */ /* Data for compadd and addmatches() */

View File

@ -2080,6 +2080,9 @@ addmatches(Cadata dat, char **argv)
/* Select the group in which to store the matches. */ /* Select the group in which to store the matches. */
gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT : 0) | gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT : 0) |
((dat->aflags & CAF_MATSORT) ? CGF_MATSORT : 0) |
((dat->aflags & CAF_NUMSORT) ? CGF_NUMSORT : 0) |
((dat->aflags & CAF_REVSORT) ? CGF_REVSORT : 0) |
((dat->aflags & CAF_UNIQALL) ? CGF_UNIQALL : 0) | ((dat->aflags & CAF_UNIQALL) ? CGF_UNIQALL : 0) |
((dat->aflags & CAF_UNIQCON) ? CGF_UNIQCON : 0)); ((dat->aflags & CAF_UNIQCON) ? CGF_UNIQCON : 0));
if (dat->group) { if (dat->group) {
@ -3034,8 +3037,9 @@ begcmgroup(char *n, int flags)
HEAP_ERROR(p->heap_id); HEAP_ERROR(p->heap_id);
} }
#endif #endif
if (p->name && if (p->name && flags ==
flags == (p->flags & (CGF_NOSORT|CGF_UNIQALL|CGF_UNIQCON)) && (p->flags & (CGF_NOSORT|CGF_UNIQALL|CGF_UNIQCON|
CGF_MATSORT|CGF_NUMSORT|CGF_REVSORT)) &&
!strcmp(n, p->name)) { !strcmp(n, p->name)) {
mgroup = p; mgroup = p;
@ -3118,32 +3122,35 @@ addexpl(int always)
/* The comparison function for matches (used for sorting). */ /* The comparison function for matches (used for sorting). */
static int matchorder;
/**/ /**/
static int static int
matchcmp(Cmatch *a, Cmatch *b) matchcmp(Cmatch *a, Cmatch *b)
{ {
if ((*a)->disp && !((*a)->flags & CMF_MORDER)) { const char *as, *bs;
if ((*b)->disp) { int cmp = !!(*b)->disp - !!(*a)->disp;
if ((*a)->flags & CMF_DISPLINE) { int sortdir = (matchorder & CGF_REVSORT) ? -1 : 1;
if ((*b)->flags & CMF_DISPLINE)
return strcmp((*a)->disp, (*b)->disp);
else
return -1;
} else {
if ((*b)->flags & CMF_DISPLINE)
return 1;
else
return strcmp((*a)->disp, (*b)->disp);
}
}
return -1;
}
if ((*b)->disp && !((*b)->flags & CMF_MORDER))
return 1;
return zstrcmp((*a)->str, (*b)->str, (SORTIT_IGNORING_BACKSLASHES| /* if match sorting selected or we have no display strings */
(isset(NUMERICGLOBSORT) ? if ((matchorder & CGF_MATSORT) || (!cmp && !(*a)->disp)) {
SORTIT_NUMERICALLY : 0))); as = (*a)->str;
bs = (*b)->str;
} else {
if (cmp) /* matches with display strings come first */
return cmp;
cmp = ((*b)->flags & CMF_DISPLINE) - ((*a)->flags & CMF_DISPLINE);
if (cmp) /* sort one-per-line display strings first */
return cmp;
as = (*a)->disp;
bs = (*b)->disp;
}
return sortdir * zstrcmp(as, bs, SORTIT_IGNORING_BACKSLASHES|
((isset(NUMERICGLOBSORT) ||
matchorder & CGF_NUMSORT) ? SORTIT_NUMERICALLY : 0));
} }
/* This tests whether two matches are equal (would produce the same /* This tests whether two matches are equal (would produce the same
@ -3205,6 +3212,7 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp)
} else { } else {
if (!(flags & CGF_NOSORT)) { if (!(flags & CGF_NOSORT)) {
/* Now sort the array (it contains matches). */ /* Now sort the array (it contains matches). */
matchorder = flags;
qsort((void *) rp, n, sizeof(Cmatch), qsort((void *) rp, n, sizeof(Cmatch),
(int (*) _((const void *, const void *)))matchcmp); (int (*) _((const void *, const void *)))matchcmp);

View File

@ -558,12 +558,53 @@ parse_class(Cpattern p, char *iptr)
return iptr; return iptr;
} }
static struct { char *name; int abbrev; int oflag; } orderopts[] = {
{ "nosort", 2, CAF_NOSORT },
{ "match", 3, CAF_MATSORT },
{ "numeric", 3, CAF_NUMSORT },
{ "reverse", 3, CAF_REVSORT }
};
/* Parse the option to compadd -o, if flags is non-NULL set it
* returns -1 if the argument isn't a valid ordering, 0 otherwise */
/**/
static int
parse_ordering(const char *arg, int *flags)
{
int o, fl = 0;
const char *next, *opt = arg;
do {
int found = 0;
next = strchr(opt, ',');
if (!next)
next = opt + strlen(opt);
for (o = sizeof(orderopts)/sizeof(*orderopts) - 1; o >= 0 &&
!found; --o)
{
if ((found = next - opt >= orderopts[o].abbrev &&
!strncmp(orderopts[o].name, opt, next - opt)))
fl |= orderopts[o].oflag;
}
if (!found) {
if (flags) /* default to "match" */
*flags = CAF_MATSORT;
return -1;
}
} while (*next && ((opt = next + 1)));
if (flags)
*flags |= fl;
return 0;
}
/**/ /**/
static int static int
bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
{ {
struct cadata dat; struct cadata dat;
char *mstr = NULL; /* argument of -M options, accumulated */ char *mstr = NULL; /* argument of -M options, accumulated */
char *oarg = NULL; /* argument of -o option */
int added; /* return value */ int added; /* return value */
Cmatcher match = NULL; Cmatcher match = NULL;
@ -572,7 +613,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
return 1; return 1;
} }
dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.mesg = dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.mesg =
dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp = dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp =
dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL; dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL;
dat.match = NULL; dat.match = NULL;
dat.flags = 0; dat.flags = 0;
@ -587,6 +628,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
} }
for (p = *argv + 1; *p; p++) { for (p = *argv + 1; *p; p++) {
char *m = NULL; /* argument of -M option (this one only) */ char *m = NULL; /* argument of -M option (this one only) */
int order = 0; /* if -o found (argument to which is optional) */
char **sp = NULL; /* the argument to an option should be copied char **sp = NULL; /* the argument to an option should be copied
to *sp. */ to *sp. */
const char *e; /* error message */ const char *e; /* error message */
@ -710,7 +752,11 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
dat.flags |= CMF_DISPLINE; dat.flags |= CMF_DISPLINE;
break; break;
case 'o': case 'o':
dat.flags |= CMF_MORDER; /* we honour just the first -o option but need to skip
* over a valid argument to subsequent -o options */
order = oarg ? -1 : 1;
sp = &oarg;
/* no error string because argument is optional */
break; break;
case 'E': case 'E':
if (p[1]) { if (p[1]) {
@ -741,15 +787,18 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
if (sp) { if (sp) {
if (p[1]) { if (p[1]) {
/* Pasted argument: -Xfoo. */ /* Pasted argument: -Xfoo. */
if (!*sp) if (!*sp) /* take first option only */
*sp = p + 1; *sp = p + 1;
p += strlen(p+1); if (!order || !parse_ordering(oarg, order == 1 ? &dat.aflags : NULL))
p += strlen(p+1);
} else if (argv[1]) { } else if (argv[1]) {
/* Argument in a separate word: -X foo. */ /* Argument in a separate word: -X foo. */
argv++; argv++;
if (!*sp) if (!*sp)
*sp = *argv; *sp = *argv;
} else { if (order && parse_ordering(oarg, order == 1 ? &dat.aflags : NULL))
--argv;
} else if (!order) {
/* Missing argument: argv[N] == "-X", argv[N+1] == NULL. */ /* Missing argument: argv[N] == "-X", argv[N+1] == NULL. */
zwarnnam(name, e, *p); zwarnnam(name, e, *p);
zsfree(mstr); zsfree(mstr);

View File

@ -138,6 +138,46 @@ F:regression test workers/31611
>FI:{\|foo} >FI:{\|foo}
>FI:{\~foo} >FI:{\~foo}
comptesteval "_tst() { compadd -onum,rev -J versions r1.10 r1.1 r1.2 r2.3 r2.34 }"
comptest $'tst r\t'
0:reverse numeric sorting of matches
>line: {tst r}{}
>NO:{r2.34}
>NO:{r2.3}
>NO:{r1.10}
>NO:{r1.2}
>NO:{r1.1}
comptesteval "_tst() { local expl; _wanted times expl time compadd -o match r1.10 r1.2 r2.3 r2.34 }"
comptesteval "zstyle ':completion:*:tst:*' sort reverse numeric"
comptest $'tst r\t'
0:reverse numeric sorting of matches via a style
>line: {tst r}{}
>DESCRIPTION:{time}
>NO:{r2.34}
>NO:{r2.3}
>NO:{r1.10}
>NO:{r1.2}
comptesteval "_tst() { local disp=(a b c); compadd -o -J letters -d disp 3 2 1 }"
comptest $'tst \t'
0:sort in match rather than display name order
>line: {tst }{}
>NO:{c}
>NO:{b}
>NO:{a}
comptesteval "_tst() { local expl; _wanted times expl time compadd 3am 12pm 3pm 10pm }"
comptesteval "zstyle ':completion:*:tst:*' sort false"
comptest $'tst \t'
0:sorting disabled via the sort style
>line: {tst }{}
>DESCRIPTION:{time}
>NO:{3am}
>NO:{12pm}
>NO:{3pm}
>NO:{10pm}
%clean %clean
zmodload -ui zsh/zpty zmodload -ui zsh/zpty