diff --git a/ChangeLog b/ChangeLog index bb8b73085..d7b225d42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2021-11-24 Oliver Kiddle + + * 49597: Completion/Base/Core/_description, Doc/Zsh/compsys.yo, + Completion/Base/Utility/_numbers, Completion/BSD/Command/_ipfw, + Completion/Linux/Command/_btrfs, Completion/Unix/Command/_dd, + Completion/Unix/Command/_git, Completion/Unix/Command/_head, + Completion/Unix/Command/_killall, Completion/Unix/Command/_pv, + Completion/Unix/Command/_rclone, Completion/Unix/Command/_rsync, + Completion/Unix/Command/_stdbuf, Completion/Unix/Command/_tail, + Completion/Unix/Command/_timeout, Completion/Unix/Command/_zfs, + Completion/X/Command/_xset: add a helper for completing numbers + with unit suffixes and separate out defaults, ranges and units + in completion descriptions + 2021-11-22 Jun-ichi Takimoto * 49586: Src/hist.c: fix :a and :A modifiers (with PWD="/") on diff --git a/Completion/BSD/Command/_ipfw b/Completion/BSD/Command/_ipfw index 2354a70fe..49d0ef1e8 100644 --- a/Completion/BSD/Command/_ipfw +++ b/Completion/BSD/Command/_ipfw @@ -249,8 +249,8 @@ actions=( $'/(pipe|queue|sched)[ \t\0]/' -'pqs=${match%?}' ':dummynet-commands:dummynet configuration:$ca pipe queue sched' $word ': _message -e numbers number' $word ':options:config:$ca config' - \( $'/bw[ \t\0]/' \( $'/<->/' ': _guard "[0-9]#" bandwidth' - $word ':units:unit:compadd -M "m:{a-z}={A-Z}" {K,M,G}{bit,Byte}/s' + \( $'/bw[ \t\0]/' + \( $word ':bandwidths: :_numbers -M "m:{a-z}={A-Z}" bandwidth {K,M,G}{bit,Byte}/s' \| $word ':devices:device:_net_interfaces -qS " "' \) \| $'/delay[ \t\0]/' $word ': _message -e numbers "propagation delay (ms)"' \| $'/burst[ \t\0]/' $word ': _message -e numbers "size (bytes)"' diff --git a/Completion/Base/Core/_description b/Completion/Base/Core/_description index 5b54484c7..368b41ee2 100644 --- a/Completion/Base/Core/_description +++ b/Completion/Base/Core/_description @@ -2,6 +2,7 @@ local name nopt xopt format gname hidden hide match opts tag local -a ign gropt sort +local -a match mbegin mend opts=() @@ -78,6 +79,13 @@ shift 2 if [[ -z "$1" && $# -eq 1 ]]; then format= elif [[ -n "$format" ]]; then + if [[ -z $2 ]]; then + argv+=( h:${1%%( ##\((#b)([^\)]#[^0-9-][^\)]#)(#B)\)|)( ##\((#b)([0-9-]##)(#B)\)|)( ##\[(#b)([^\]]##)(#B)\]|)} ) + [[ -n $match[1] ]] && argv+=( m:$match[1] ) + [[ -n $match[2] ]] && argv+=( r:$match[2] ) + [[ -n $match[3] ]] && argv+=( o:$match[3] ) + fi + zformat -F format "$format" "d:$1" "${(@)argv[2,-1]}" fi diff --git a/Completion/Base/Utility/_numbers b/Completion/Base/Utility/_numbers new file mode 100644 index 000000000..97bb8b4c8 --- /dev/null +++ b/Completion/Base/Utility/_numbers @@ -0,0 +1,87 @@ +#autoload + +# Usage: _numbers [compadd options] [-t tag] [-f|-N] [-u units] [-l min] [-m max] \ +# [-d default] ["description"] [unit-suffix...] + +# -t : specify a tag (defaults to 'numbers') +# -u : indicate the units, e.g. seconds +# -l : lowest possible value +# -m : maximum possible value +# -d : default value +# -N : allow negative numbers (implied by range including a negative) +# -f : allow decimals (float) + +# For a unit-suffix, an initial colon indicates a unit that asserts the default +# otherwise, colons allow for descriptions, e.g: + +# :s:seconds m:minutes h:hours + +# unit-suffixes are not sorted by the completion system when listed +# Specify them in order of magnitude, this tends to be ascending unless +# the default is of a higher magnitude, in which case, descending. +# So for, example +# bytes kB MB GB +# s ms us ns +# Where the compadd options include matching control or suffixes, these +# are applied to the units + +# For each unit-suffix, the format style is looked up with the +# unit-suffixes tag and the results concatenated. Specs used are: +# x : the suffix +# X : suffix description +# d : indicate suffix is for the default unit +# i : list index +# r : reverse list index +# The latter three of these are useful with ternary expressions. + +# _description is called with the x token set to make the completed +# list of suffixes available to the normal format style + +local desc tag range suffixes suffix suffixfmt pat='<->' partial='' +local -a expl formats +local -a default max min keep tags units +local -i i +local -A opts + +zparseopts -K -D -A opts M+:=keep q:=keep s+:=keep S+:=keep J+: V+: 1 2 o+: n F: x+: X+: \ + t:=tags u:=units l:=min m:=max d:=default f=type e=type N=type + +desc="${1:-number}" tag="${tags[2]:-numbers}" +(( $# )) && shift + +[[ -n ${(M)type:#-f} ]] && pat='(<->.[0-9]#|[0-9]#.<->|<->)' partial='(|.)' +[[ -n ${(M)type:#-N} || $min[2] = -* || $max[2] = -* ]] && \ + pat="(|-)$pat" partial="(|-)$partial" + +if (( $#argv )) && compset -P "$pat"; then + zstyle -s ":completion:${curcontext}:units" list-separator sep || sep=-- + _description -V units expl unit + disp=( ${${argv#:}/:/ $sep } ) + compadd -M 'r:|/=* r:|=*' -d disp "$keep[@]" "$expl[@]" - ${${argv#:}%%:*} + return +elif [[ -prefix $~pat || $PREFIX = $~partial ]]; then + formats=( "h:$desc" ) + (( $#units )) && formats+=( m:${units[2]} ) desc+=" ($units[2])" + (( $#min )) && range="$min[2]-" + (( $#max )) && range="${range:--}$max[2]" + [[ -n $range ]] && formats+=( r:$range ) desc+=" ($range)" + (( $#default )) && formats+=( o:${default[2]} ) desc+=" [$default[2]]" + + zstyle -s ":completion:${curcontext}:unit-suffixes" format suffixfmt || \ + suffixfmt='%(d.%U.)%x%(d.%u.)%(r..|)' + for ((i=0;i<$#;i++)); do + zformat -f suffix "$suffixfmt" "x:${${argv[i+1]#:}%%:*}" \ + "X:${${argv[i+1]#:}#*:}" "d:${#${argv[i+1]}[1]#:}" \ + i:i r:$(( $# - i - 1)) + suffixes+="$suffix" + done + [[ -n $suffixes ]] && formats+=( x:$suffixes ) + + _comp_mesg=yes + _description -x $tag expl "$desc" $formats + [[ $compstate[insert] = *unambiguous* ]] && compstate[insert]= + compadd "$expl[@]" + return 0 +fi + +return 1 diff --git a/Completion/Linux/Command/_btrfs b/Completion/Linux/Command/_btrfs index bb0f724e6..65cf067aa 100644 --- a/Completion/Linux/Command/_btrfs +++ b/Completion/Linux/Command/_btrfs @@ -147,16 +147,16 @@ while (( $#state )); do '--tbytes[show sizes in TiB, or TB with --si]' ) ;| - filesystem:resize) args+=( '1:size:_guard "(|+|-)[0-9]#[GKM]"' '2:path:->mounts' );; + filesystem:resize) args+=( '1: :_numbers -u bytes -N size K M G T P E' '2:path:->mounts' );; filesystem:defragment) args+=( '!-v' '-r[defragment files recursively]' '-c+[compress files while defragmenting]::compression algorithm:(zlib lzo zstd)' '-r[defragment files recursively]' '-f[flush after defragmenting]' - '-s[start position]:byte position' - '-l[defragment limited number of bytes]:length (bytes)' - '-t[defragment only files over a certain size]:minimum size (bytes) [32M]' + '-s[start position]: :_numbers -u bytes -d "beginning of file" offset K M G T P E' + '-l[defragment limited number of bytes]: :_numbers -u bytes length K M G T P E' + '-t[defragment only extents up to a certain size]: :_numbers -u bytes -d 32M "maximum extent size" K M G T P E' '*:file:_files' ) ;; diff --git a/Completion/Unix/Command/_dd b/Completion/Unix/Command/_dd index e5c5e63ce..10682bc8e 100644 --- a/Completion/Unix/Command/_dd +++ b/Completion/Unix/Command/_dd @@ -1,18 +1,19 @@ #compdef dd gdd -local -a vals conv flags +local -a vals conv flags units local variant +units=( w:word b:block k:1024 m g t ) _pick_variant -r variant gnu=GNU $OSTYPE --version vals=( - '(ibs obs)bs[block size]:block size (bytes)' - 'cbs[conversion buffer size]:buffer size (bytes)' + '(ibs obs)bs[block size]: :_numbers -u bytes "block size" $units' + 'cbs[conversion buffer size]: :_numbers -u bytes "buffer size" $units' 'conv[specify conversions to apply]: :_values -s , conversion $conv' 'count[number of input blocks to copy]:blocks' - '(bs)ibs[input block size]:block size (bytes)' + '(bs)ibs[input block size]: :_numbers -u bytes -d 512 "block size" $units' 'if[specify input file]:input file:_tilde_files' - '(bs)obs[output block size]:block size (bytes)' + '(bs)obs[output block size]: :_numbers -u bytes -d 512 "block size" $units' 'of[specify output file]:output file:_tilde_files' 'seek[output blocks initially skipped]:blocks' 'skip[input blocks initially skipped]:blocks' @@ -63,7 +64,7 @@ case $variant in freebsd*) vals+=( 'fillchar[specify padding character]:character' - 'speed[limit copying speed]:speed (bytes/second)' + 'speed[limit copying speed]: :_numbers -u bytes/second speed $units' ) conv+=( '(pareven parnone parodd parset)'{pareven,parnone,parodd,parset} @@ -75,6 +76,7 @@ case $variant in ) flags+=( fullblock noatime nocache count_bytes skip_bytes seek_bytes ) conv+=( excl nocreat fdatasync fsync ) + units=( c:1 w:2 b:512 kB:1000 K:1024 MB:1000^2 M:1024\^2 GB G TB T PB P EB E ZB Z YB Y ) ;; netbsd*) vals+=( diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git index 7c7fb22bc..c757376b0 100644 --- a/Completion/Unix/Command/_git +++ b/Completion/Unix/Command/_git @@ -3720,8 +3720,8 @@ _git-fast-import () { now\:"use current time and timezone"' \ '--done[terminate with error if there is no "done" command at the end of the stream]' \ '--force[force updating modified existing branches]' \ - '--max-pack-size=-[maximum size of each packfile]: : __git_guard_bytes' \ - '--big-file-threshold=-[maximum size of blob to create deltas for]: : __git_guard_bytes' \ + '--max-pack-size=-[maximum size of each packfile]: : __git_guard_bytes -d unlimited size' \ + '--big-file-threshold=-[maximum size of blob to create deltas for]: : __git_guard_bytes -d 512m size' \ '--depth=-[maximum delta depth for blob and tree deltification]: :__git_guard_number "maximum delta depth"' \ '--active-branches=-[maximum number of branches to maintain active at once]: :__git_guard_number "maximum number of branches"' \ '--export-marks=-[dump internal marks table when complete]: :_files' \ @@ -7506,7 +7506,7 @@ __git_guard_number () { (( $+functions[__git_guard_bytes] )) || __git_guard_bytes () { - _guard '[[:digit:]]#([kKmMgG]|)' ${*:-size} + _numbers -u bytes ${*:-size} k m g } (( $+functions[__git_datetimes] )) || diff --git a/Completion/Unix/Command/_head b/Completion/Unix/Command/_head index f25c97c83..0771b1e4d 100644 --- a/Completion/Unix/Command/_head +++ b/Completion/Unix/Command/_head @@ -32,20 +32,14 @@ _arguments -C -s -S $opts : $args '*:file:_files' && return 0 case $state in (number) - local mlt sign digit - mlt='multiplier:multiplier:((b\:512 K\:1024 KB\:1000 M\:1024\^2' - mlt+=' MB\:1000\^2 G\:1024\^3 GB\:1000\^3 T\:1024\^4 TB\:1000\^4))' - sign='sign:sign:((-\:"print all but the last specified bytes/lines"' - sign+=' +\:"print the first specified bytes/lines (default)"))' - digit='digits:digit:(0 1 2 3 4 5 6 7 8 9)' - if compset -P '(-|+|)[0-9]##'; then - _alternative $mlt $digit && ret=0 - elif [[ -z $PREFIX ]]; then - _alternative $sign $digit && ret=0 - elif compset -P '(+|-)'; then - _alternative $digit && ret=0 - fi - ;; + local alts + [[ -z $PREFIX ]] && alts=( + 'sign:sign:((-\:"print all but the last specified bytes/lines" +\:"print the first specified bytes/lines (default)"))' + ) + compset -P '+' + alts+=( 'numbers: :_numbers -N $state_descr b\:512 K\:1024 KB\:1000 M\:1024\^2 MB\:1000\^2 G\:1024\^3 GB\:1000\^3 T\:1024\^4 TB\:1000\^4' ) + _alternative $alts && ret=0 + ;; esac return ret diff --git a/Completion/Unix/Command/_killall b/Completion/Unix/Command/_killall index 36accb2e0..3ddd36341 100644 --- a/Completion/Unix/Command/_killall +++ b/Completion/Unix/Command/_killall @@ -38,15 +38,9 @@ if _pick_variant psmisc=PSmisc unix --version; then case $state in (time) - local -a units=( 's:seconds' 'm:minutes' 'h:hours' 'd:days' - 'w:weeks' 'M:months' 'y:years' ) - if compset -P '[0-9]##(|.[0-9]#)'; then - _alternative 'float-numbers:: _message "float number"' \ - 'units:: _describe unit units' && ret=0 - else - _message 'float number and unit' && ret=0 - fi - ;; + _numbers -fN age 's:seconds' 'm:minutes' 'h:hours' 'd:days' \ + 'w:weeks' 'M:months' 'y:years' + ;; esac return ret diff --git a/Completion/Unix/Command/_pv b/Completion/Unix/Command/_pv index 68f8e8586..d02d3a35d 100644 --- a/Completion/Unix/Command/_pv +++ b/Completion/Unix/Command/_pv @@ -25,7 +25,7 @@ _arguments -s -S $args \ '(-q --quiet)'{-q,--quiet}"[don't output any transfer information at all, useful with -L]" \ '(-W --wait)'{-W,--wait}'[display nothing until first byte transferred]' \ '(-D --delay-start -R --remote)'{-D+,--delay-start=}'[display nothing until delay has passed]:delay (seconds)' \ - '(-s --size)'{-s+,--size=}'[set estimated data size]:size (bytes):->size-unit' \ + '(-s --size)'{-s+,--size=}'[set estimated data size]: :_numbers -u bytes size K M G T' \ '(-l --line-mode -R --remote)'{-l,--line-mode}'[count lines instead of bytes]' \ '(-0 --null -l --line-mode)'{-0,--null}'[lines are null-terminated]' \ '(-i --interval)'{-i+,--interval=}'[update every after specified interval]:interval (seconds) [1]' \ @@ -34,8 +34,8 @@ _arguments -s -S $args \ '(-N --name)'{-N+,--name=}'[prefix visual information with given name]:name' \ '(-f --force -R --remote)'{-f,--force}'[output even if standard error is not a terminal]' \ '(-c --cursor -R --remote)'{-c,--cursor}'[use cursor positioning escape sequences]' \ - '(-L --rate-limit)'{-L+,--rate-limit=}'[limit transfer rate]:rate (bytes per second):->size-unit' \ - '(-B --buffer-size)'{-B+,--buffer-size=}'[use a buffer size of given size]:size (bytes):->size-unit' \ + '(-L --rate-limit)'{-L+,--rate-limit=}'[limit transfer rate]: :_numbers -u "bytes per second" rate K M G T' \ + '(-B --buffer-size)'{-B+,--buffer-size=}'[use a buffer size of given size]: :_numbers -u bytes size K M G T' \ '(-C --no-splice)'{-C,--no-splice}'[never use splice(), always use read/write]' \ '(-R --remote)*'{-E,--skip-errors}"[skip read errors in input${Edesc}]" \ '(-S --stop-at-size -R --remote)'{-S,--stop-at-size}'[stop after --size bytes have been transferred]' \ @@ -70,18 +70,6 @@ case $state in _pids $suf && ret=0 fi ;; - size-unit) - if compset -P '<->'; then - _tags values units - else - _tags values - fi - while _tags; do - _requested values && _message -e values "$state_descr" && ret=0 - _requested units expl unit compadd -o nosort - K M G T && ret=0 - (( ret )) || break - done - ;; esac return ret diff --git a/Completion/Unix/Command/_rclone b/Completion/Unix/Command/_rclone index 27b4dd926..a2e3429f5 100644 --- a/Completion/Unix/Command/_rclone +++ b/Completion/Unix/Command/_rclone @@ -62,7 +62,7 @@ _arguments -C \ '--backup-dir[make backups into hierarchy based at specified directory]:directory:_directories' \ '--bind[specify socal address to bind to for outgoing connections]:IPv4, IPv6 or name' \ '--buffer-size[specify in memory buffer size when reading files for each --transfer]:size [16M]' \ - '--bwlimit[specify bandwidth limit]:BwTimetable (kBytes/s or b|k|M|G suffix)' \ + '--bwlimit[specify bandwidth limit]: :_numbers -u kBytes/s limit b k M G' \ '--cache-dir[specify directory rclone will use for caching]:directory [~/.cache/rclone]:_directories' \ '--checkers[specify number of checkers to run in parallel]:number [8]': \ '(-c --checksum)'{-c,--checksum}'[skip based on checksum & size, not mod-time & size]' \ @@ -99,15 +99,15 @@ _arguments -C \ '--log-format[specify comma separated list of log format options]:string ["date,time"]' \ '--log-level[specify log level]:string [NOTICE]:(DEBUG INFO NOTICE ERROR)' \ '--low-level-retries[number of low level retries to do]:int [10]' \ - '--max-age[only transfer files younger than this in s or suffix ms|s|m|h|d|w|M|y]:duration [default off]' \ + '--max-age[only transfer files younger than specified age]: :_numbers -u seconds age ms\:milliseconds \:s\:seconds m\:minutes h\:hours d\:days w\:weeks M\:months y\:years' \ '--max-backlog[maximum number of objects in sync or check backlog]:int [10000]' \ '--max-delete[when synchronizing, limit the number of deletes]:delete limit [-1]' \ '--max-depth[limit the recursion depth]:depth [-1]' \ - '--max-size[only transfer files smaller than this in k or suffix b|k|M|G]:int [default off]' \ + '--max-size[only transfer files smaller than specified size]: :_numbers -u kBytes size \:k M G' \ '--max-transfer[maximum size of data to transfer]:int [default off]' \ '--memprofile[write memory profile to file]:file:_files' \ - '--min-age[only transfer files older than this in s or suffix ms|s|m|h|d|w|M|y]:duration [default off]' \ - '--min-size[only transfer files bigger than this in k or suffix b|k|M|G]:int [default off]' \ + '--min-age[only transfer files older than specified age]: :_numbers -u seconds age ms\:milliseconds \:s\:seconds m\:minutes h\:hours d\:days w\:weeks M\:months y\:years' \ + '--min-size[only transfer files bigger than specified size]: :_numbers -u kBytes size \:k M G' \ '--modify-window[specify max time delta to be considered the same]:duration [1ns]' \ '--multi-thread-cutoff[use multi-threaded downloads for files above specified size]:size (250M)' \ '--multi-thread-streams[specify max number of streams to use for multi-threaded downloads]:number (4)' \ diff --git a/Completion/Unix/Command/_rsync b/Completion/Unix/Command/_rsync index b1a4f6046..eb906e974 100644 --- a/Completion/Unix/Command/_rsync +++ b/Completion/Unix/Command/_rsync @@ -99,7 +99,7 @@ _rsync() { _arguments -s \ '*'{-v,--verbose}'[increase verbosity]' \ {--no-v,--no-verbose}'[turn off --verbose]' \ - '--bwlimit=[limit I/O bandwidth]:limit (KiB per second)' \ + '--bwlimit=[limit I/O bandwidth]: :_numbers -f -u "KiB per second" -d 1g limit B K M G T P' \ '--outbuf=[set output buffering]:buffering:(none line block)' \ '--port=[specify alternate port number]:port:(873)' \ '--address=[bind to the specified address]:bind address:_bind_addresses' \ @@ -181,7 +181,7 @@ _rsync() { {--no-W,--no-whole-file}'[turn off --whole-file]' \ '(--cc --checksum-choice)'{--cc,--checksum-choice}'=[choose the checksum algorithms]:algorithm:_sequence -n 2 compadd - auto md4 md5 none' \ '(-x --one-file-system)'{-x,--one-file-system}"[don't cross filesystem boundaries]" \ - '(-B --block-size)'{-B+,--block-size=}'[force a fixed checksum block-size]:block size (bytes)' \ + '(-B --block-size)'{-B+,--block-size=}'[force a fixed checksum block-size]: :_numbers -f -u bytes -d 1g "block size" B K M G T P' \ '(-e --rsh)'{-e+,--rsh=}'[specify the remote shell to use]:remote-shell command:(rsh ssh)' \ '--rsync-path=[specify path to rsync on the remote machine]:remote command' \ '--ignore-existing[ignore files that already exist on receiving side]' \ @@ -199,10 +199,10 @@ _rsync() { '--force-change[affect user-/system-immutable files/dirs]' \ '--force-uchange[affect user-immutable files/dirs]' \ '--force-schange[affect system-immutable files/dirs]' \ - '--max-delete=[do not delete more than NUM files]:number' \ - '--max-size=[do not transfer any file larger than specified size]:number' \ + "--max-delete=[don't delete more than NUM files]: :_numbers -f -u bytes size B K M G T P" \ + "--max-size=[don't transfer any file larger than specified size]: :_numbers -f -u bytes size B K M G T P" \ '--min-size=[do not transfer any file smaller than specified size]:number' \ - '--max-alloc=[set limit to individual memory allocation]:size (bytes) [1g]' \ + '--max-alloc=[set limit to individual memory allocation]: :_numbers -f -u bytes -d 1g size B K M G T P' \ '(-P)--partial[keep partially transferred files]' \ '--no-partial[turn off --partial]' \ '--partial-dir=[put a partially transferred file into specified directory]:directory:_directories' \ diff --git a/Completion/Unix/Command/_stdbuf b/Completion/Unix/Command/_stdbuf index a18938ee1..4b7d98ba0 100644 --- a/Completion/Unix/Command/_stdbuf +++ b/Completion/Unix/Command/_stdbuf @@ -7,7 +7,9 @@ short=( -e -i -o ) long=( --error --input --output ) buf=( err in out ) -opt='[set initial buffering for std${buf[i]}]:mode or size:((0\:unbuffered L\:line\ buffered' +opt='[set initial buffering for std${buf[i]}]: : _alternative + "sizes\: \: _numbers -u bytes size k M G" + "modes\:mode\:((0\:unbuffered L\:line\ buffered' if _pick_variant gnu=GNU freebsd --version; then gnu=1 args=( @@ -17,7 +19,7 @@ if _pick_variant gnu=GNU freebsd --version; then else opt+=' B\:fully\ buffered' fi -opt+='))' +opt+='))"' for ((i=1;i<=3;i++)); do args+=( "(${long[i]})${short[i]}+${(e)opt}" ) diff --git a/Completion/Unix/Command/_tail b/Completion/Unix/Command/_tail index 6d6e9b2d5..e54a0b06e 100644 --- a/Completion/Unix/Command/_tail +++ b/Completion/Unix/Command/_tail @@ -53,20 +53,14 @@ _arguments -C -s -S $opts : $args '*:file:_files' && return case $state in (number) - local mlt sign digit - mlt='multipliers:multiplier:((b\:512 K\:1024 KB\:1000 M\:1024\^2' - mlt+=' MB\:1000\^2 G\:1024\^3 GB\:1000\^3 T\:1024\^4 TB\:1000\^4))' - sign='signs:sign:((+\:"start at the specified byte/line"' - sign+=' -\:"output the last specified bytes/lines (default)"))' - digit='digits:digit:(0 1 2 3 4 5 6 7 8 9)' - if compset -P '(-|+|)[0-9]##'; then - _alternative $mlt $digit && ret=0 - elif [[ -z $PREFIX ]]; then - _alternative $sign $digit && ret=0 - elif compset -P '(+|-)'; then - _alternative $digit && ret=0 - fi - ;; + local alts + [[ -z $PREFIX ]] && alts=( + 'sign:sign:((-\:"print all but the last specified bytes/lines" +\:"print the first specified bytes/lines (default)"))' + ) + compset -P '+' + alts+=( 'numbers: :_numbers -N $state_descr b\:512 K\:1024 KB\:1000 M\:1024\^2 MB\:1000\^2 G\:1024\^3 GB\:1000\^3 T\:1024\^4 TB\:1000\^4' ) + _alternative $alts && ret=0 + ;; esac return ret diff --git a/Completion/Unix/Command/_timeout b/Completion/Unix/Command/_timeout index 2235fa5ec..c041283ac 100644 --- a/Completion/Unix/Command/_timeout +++ b/Completion/Unix/Command/_timeout @@ -16,5 +16,5 @@ _arguments -S -A "-" $args \ "--foreground[don't propagate timeout to the command children]" \ '(-s --signal)'{-s,--signal}'[specify the signal to send on timeout]:signal:_signals' \ '(-k --kill-after)'{-k,--kill-after}'[followup first signal with SIGKILL if command persists after specified time]:time' \ - '1: :_guard "[0-9.]#([smhd]|)" duration' \ + '1: :_numbers -f -u seconds duration :s:seconds m:minutes h:hours d:days' \ '*:::command:_normal' diff --git a/Completion/Unix/Command/_zfs b/Completion/Unix/Command/_zfs index 452e1160d..51da9170b 100644 --- a/Completion/Unix/Command/_zfs +++ b/Completion/Unix/Command/_zfs @@ -162,12 +162,20 @@ _zfs() { "multilevel:value:(on off)" "nbmand:value:(on off)" "primarycache:value:(all none metadata)" - "quota:number or 'none':{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ $PREFIX == quota= ]]; then _wanted none expl 'number or none' compadd none; else _wanted none expl 'quota' compadd none; fi}" + "quota: : _alternative \ + 'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \ + 'properties:property:(none)'" "readonly:value:(on off)" "recordsize:value:(512 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M)" - "refquota:number or 'none':{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ $PREFIX == refquota= ]]; then _wanted none expl 'number or none' compadd none; else _wanted none expl 'refquota' compadd none; fi}" - "refreservation:number or 'none':{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ $PREFIX == refreservation= ]]; then _wanted none expl 'number or none' compadd none; else _wanted none expl 'refreservation' compadd none; fi}" - "reservation:value:{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ $PREFIX == reservation= ]]; then _wanted none expl 'number or none' compadd none; else _wanted none expl 'reservation' compadd none; fi}" + "refquota: : _alternative \ + 'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \ + 'properties:property:(none)'" + "refreservation: : _alternative \ + 'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \ + 'properties:property:(auto none)'" + "reservation: : _alternative \ + 'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \ + 'properties:property:(none)'" "rstchown:value:(on off)" "secondarycache:value:(all none metadata)" "setuid:value:(on off)" @@ -238,8 +246,8 @@ _zfs() { ':filesystem:_zfs_dataset -t fs -e "parent dataset"' \ - set2 \ '-s[Create sparse volume]' \ - '-b[Set volblocksize]:blocksize:' \ - '-V[Set size]:size:' \ + '-b+[set volblocksize]: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes blocksize :B {k,M,G,T,P,E,Z}{,B}' \ + '-V+[set size]: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \ ':volume:_zfs_dataset -t fs -e "parent dataset"' ;; diff --git a/Completion/X/Command/_xset b/Completion/X/Command/_xset index b35a6466b..adda47f01 100644 --- a/Completion/X/Command/_xset +++ b/Completion/X/Command/_xset @@ -91,8 +91,8 @@ _regex_arguments _xset_parse \ \( "/(blank|noblank|expose|noexpose|default|on|activate|reset)$nul/" \ ':option-s:screen saver:(blank noblank expose noexpose default on activate reset off)' \ \| "/off$nul/" \( "/off$nul/" ':option-s-off-period:period off:(off)' \| \) \ - \| "/[0-9]##$nul/" ':option-s-timeout:length:' \ - \( "/[0-9]##$nul/" ':option-s-period:period:' \ + \| "/[0-9]##$nul/" ':option-s-timeout: :_numbers -u seconds length' \ + \( "/[0-9]##$nul/" ':option-s-period: :_numbers -u seconds period' \ \| \) \ \| \) \ \| "/-r$nul/" "$guard" \ diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 8c6bf9c40..40238c4b9 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -4496,8 +4496,22 @@ not contain an explanation string to be displayed above the matches. If tt(_description) is called with more than three arguments, the additional var(spec)s should be of the form `var(char)tt(:)var(str)'. These supply escape sequence replacements for the tt(format) style: -every appearance of `tt(%)var(char)' will be -replaced by var(string). +every appearance of `tt(%)var(char)' will be replaced by var(string). +If no additional var(spec)s are given but the description in var(descr) +conforms to a common form then further escape sequences are set for +elements of that description. These elements correspond to a default +value (`tt(%o)'), the units (`tt(%m)') range of acceptable values +(`tt(%r)') and the remaining initial part of the description (`tt(%h)'). +The form the description takes consists of specifying the units and +range in parentheses and the default value in square brackets, for +example: + +example(_description times expl 'timeout (seconds) (0-60) [20]') + +It is possible to use tt(zformat) conditional expressions when styling +these elements. So, for example, to add `tt(default:)' as a tag but only +when there is a default value to show, the tt(format) style might +include `tt(%(o.default: %o.))'. If the tt(-x) option is given, the description will be passed to tt(compadd) using the tt(-x) option instead of the default tt(-X). This @@ -4773,6 +4787,69 @@ checked. If it is set completion is terminated at that point even if no matches have been found. This is the same effect as in the tt(-first-) context. ) +findex(_numbers) +item(tt(_numbers) [ var(option) ... ] [ var(description) ] [ var(suffix) ... ])( +This can be used where a number is followed by a suffix to indicate the units. +The unit suffixes are completed and can also be included in the description +used when completion is invoked for the preceding number. + +In addition to common tt(compadd) options, tt(_numbers) accepts the following +options: + +startitem() +item(tt(-t) var(tag))( +Specify a tag to use instead of the default of tt(numbers). +) +item(tt(-u) var(units))( +Indicate the default units for the number, e.g. tt(bytes). +) +item(tt(-l) var(min))( +Specify the lowest possible value for the number. +) +item(tt(-m) var(max))( +Specify the highest possible value for the number. +) +item(tt(-d) var(default))( +Specify the default value. +) +item(tt(-N))( +Allow negative numbers. This is implied if the range includes a negative. +) +item(tt(-f))( +Allow decimal numbers. +) +enditem() + +Where a particular suffix represents the default units for a number, it +should be prefixed with a colon. Additionally, suffixes can be followed +by a colon and a description. So for example, the following allows the +age of something to be specified, either in seconds or with an optional +suffix with a longer unit of time: + +example(_numbers -u seconds age :s:seconds m:minutes h:hours d:days) + +It is typically helpful for units to be presented in order of magnitude +when completed. To facilitate this, the order in which they are given +is preserved. + +When the tt(format) style is looked up with the tt(descriptions) tag or +the tag specified with tt(-t), the list of suffixes is available as a +`tt(%x)' escape sequence. This is in addition to the usual sequences +documented under the tt(format) style. The form this list takes can also +be configured. To this end, the tt(format) style is first looked up with +the tag tt(unit-suffixes). The retrieved format is applied to each +suffix in turn and the results are then concatenated to form the +completed list. For the tt(unit-suffixes) format, `tt(%x)' expands to +the individual suffix and `tt(%X)' to its description. tt(%d)' indicates +a default suffix and can be used in a condition. The index and reverse +index are set in `tt(%i)' and `tt(%r)' respectively and are useful for +text included only with the first and last suffixes in the list. So for +example, the following joins the suffixes together as a comma-separated +list: + +example(zstyle ':completion:*:unit-suffixes' format '%x%(r::,)') +) + findex(_options) item(tt(_options))( This can be used to complete the names of shell options. It provides a