From 485a008075ce19bfdf19922c803d1637ebb5255e Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sat, 23 Feb 2008 00:10:24 +0000 Subject: 24585: completion for glob qualifiers plus bug fix for _alternative --- ChangeLog | 11 ++ Completion/Base/Utility/_alternative | 2 +- Completion/Unix/Type/_path_files | 17 ++- Completion/Zsh/Type/_delimiters | 16 +++ Completion/Zsh/Type/_globqual_delims | 24 ++++ Completion/Zsh/Type/_globquals | 233 +++++++++++++++++++++++++++++++++ Completion/Zsh/Type/_history_modifiers | 84 ++++++++++++ Doc/Zsh/compsys.yo | 9 ++ 8 files changed, 393 insertions(+), 3 deletions(-) create mode 100644 Completion/Zsh/Type/_delimiters create mode 100644 Completion/Zsh/Type/_globqual_delims create mode 100644 Completion/Zsh/Type/_globquals create mode 100644 Completion/Zsh/Type/_history_modifiers diff --git a/ChangeLog b/ChangeLog index 18b351bee..7ad5991c9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-02-23 Peter Stephenson + + * 24585: Completion/Base/Utility/_alternative, + Completion/Unix/Type/_path_files, + Completion/Zsh/Type/_delimiters, + Completion/Zsh/Type/_globqual_delims, + Completion/Zsh/Type/_globquals, + Completion/Zsh/Type/_history_modifiers, Doc/Zsh/compsys.yo: + completion for glob qualifiers plus bug fix for message-only + completion in _alternative. + 2008-02-22 Peter Stephenson * unposted: Completion/Unix/Command/_perforce: new option diff --git a/Completion/Base/Utility/_alternative b/Completion/Base/Utility/_alternative index c7b71d9bc..bfb34a604 100644 --- a/Completion/Base/Utility/_alternative +++ b/Completion/Base/Utility/_alternative @@ -75,7 +75,7 @@ while _tags; do done for descr in "$mesgs[@]"; do - _message -e "${descr%%:*}" "${desc#*:}" + _message -e "${descr%%:*}" "${descr#*:}" done return 1 diff --git a/Completion/Unix/Type/_path_files b/Completion/Unix/Type/_path_files index 4176005c3..e75e81efd 100644 --- a/Completion/Unix/Type/_path_files +++ b/Completion/Unix/Type/_path_files @@ -6,8 +6,9 @@ local linepath realpath donepath prepath testpath exppath skips skipped local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre local pats haspats ignore pfx pfxsfx sopt gopt opt sdirs ignpar cfopt listsfx -local nm=$compstate[nmatches] menu matcher mopts sort match mid accex fake +local nm=$compstate[nmatches] menu matcher mopts sort mid accex fake local listfiles listopts tmpdisp +local -a match mbegin mend typeset -U prepaths exppaths @@ -349,7 +350,19 @@ for prepath in "$prepaths[@]"; do tmp2=( "$tmp1[@]" ) - if [[ "$tpre$tsuf" = */* ]]; then + # Look for glob qualifiers. + # Extra nastiness to be careful about a quoted parenthesis. + # The initial tests look for parentheses with zero or an + # even number of backslashes in front. + # The later test looks for an outstanding quote. + if [[ ( -o bareglobqual && \ + "$tpre/$tsuf" = (#b)((*[^\\]|)(\\\\)#\()([^\)]#) || \ + -o extendedglob && \ + "$tpre/$tsuf" = (#b)((*[^\\]|)(\\\\)#"(#q")([^\)]#) \ + ) && -z $compstate[quote] ]]; then + compset -p ${#match[1]} + _globquals + elif [[ "$tpre$tsuf" = */* ]]; then compfiles -P$cfopt tmp1 accex "$skipped" "$_matcher $matcher[2]" "$sdirs" fake elif [[ "$sopt" = *[/f]* ]]; then compfiles -p$cfopt tmp1 accex "$skipped" "$_matcher $matcher[2]" "$sdirs" fake "$pats[@]" diff --git a/Completion/Zsh/Type/_delimiters b/Completion/Zsh/Type/_delimiters new file mode 100644 index 000000000..bb5bba8d0 --- /dev/null +++ b/Completion/Zsh/Type/_delimiters @@ -0,0 +1,16 @@ +#autoload + +# Simple function to offer delimiters for modifiers and qualifers. +# Single argument is tag to use. + +local expl +local -a list + +zstyle -a ":completion:${curcontext}:$1" delimiters list || + list=(: + / - %) + +if (( ${#list} )); then + _wanted delimiters expl delimiter compadd -S '' -a list +else + _message delimiter +fi diff --git a/Completion/Zsh/Type/_globqual_delims b/Completion/Zsh/Type/_globqual_delims new file mode 100644 index 000000000..bba4241e8 --- /dev/null +++ b/Completion/Zsh/Type/_globqual_delims @@ -0,0 +1,24 @@ +#autoload + +# Helper for _globquals. Sets delim to delimiter to match. + +# don't restore special parameters +compstate[restore]=no + +delim=$PREFIX[1] +compset -p 1 + +# One of matching brackets? +# These don't actually work: the parser gets very confused. +local matchl="<({[" matchr=">)}]" +integer ind=${matchl[(I)$delim]} + +(( ind )) && delim=$matchr[ind] + +if compset -P "[^$delim]#$delim"; then + # Completely matched. + return 0 +else + # Still in delimiter + return 1 +fi diff --git a/Completion/Zsh/Type/_globquals b/Completion/Zsh/Type/_globquals new file mode 100644 index 000000000..0262c8b6f --- /dev/null +++ b/Completion/Zsh/Type/_globquals @@ -0,0 +1,233 @@ +#autoload + +local state=qual expl char delim +local -a alts + +while [[ -n $PREFIX ]]; do + char=$PREFIX[1] + compset -p 1 + case $char in + ([-/F.@=p*rwxAIERWXsStUG^MTNDn,]) + # no argument + ;; + + (%) + # optional b, c + if [[ $PREFIX[1] = [bc] ]]; then + compset -p 1 + fi + ;; + + (f) + if ! compset -P "[-=+][0-7?]##"; then + if [[ -z $PREFIX ]]; then + _delimiters qualifier-f + return + elif ! _globqual_delims; then + # still completing mode spec + _message "mode spec" + return + fi + fi + ;; + + (e) + # complete/skip delimited command line + if [[ -z $PREFIX ]]; then + _delimiters qualifer-e + return + elif ! _globqual_delims; then + # still completing command to eval + compset -q + _normal + return + fi + ;; + + (+) + # complete/skip command name (no delimiters) + if [[ $PREFIX = [[:IDENT:]]# ]]; then + # either nothing there yet, or still on name + _command_names + return + fi + compset -P '[[:IDENT:]]##' + ;; + + (d) + # complete/skip device + if [[ -z $PREFIX ]]; then + _message device ID + return + fi + # It's pointless trying to complete the device. + # Simply assume it's done. + compset -p '[[:digit:]]##' + ;; + + (l) + # complete/skip link count + if [[ PREFIX = ([-+]|) ]]; then + _message link count + return + fi + # It's pointless trying to complete the link count. + # Simply assume it's done. + compset -P '([-+]|)[[:digit:]]##' + ;; + + (u) + # complete/skip UID or delimited user + if ! compset -P '[[:digit:]]##'; then + if [[ -z $PREFIX ]]; then + _delimiters qualifier-u + return + elif ! _globqual_delims; then + # still completing user + _users -S $delim + return + fi + fi + ;; + + (g) + # complete/skip GID or delimited group + if ! compset -P '[[:digit:]]##'; then + if [[ -z $PREFIX ]]; then + _delimiter qualifier-g + return + elif ! _globqual_delims; then + # still completing group + _groups -S $delim + return + fi + fi + ;; + + ([amc]) + if ! compset -P '([Mwhms]|)([-+]|)<->'; then + # complete/skip relative time spec + alts=() + if ! compset -P '[Mwhms]' && [[ -z $PREFIX ]]; then + alts+=( + "time-specifiers:time specifier:\ +((M\:months w\:weeks h\:hours m:\minutes s\:seconds))") + fi + if ! compset -P '[-+]' && [[ -z $PREFIX ]]; then + alts+=("senses:sense:((-\:less\ than +\:more\ than))") + fi + alts+=('digits:digit: ') + _alternative $alts + return + fi + ;; + + (L) + # complete/skip file size + if ! compset -P '([kKmMpP]|)([-+]|)<->'; then + # complete/skip size spec + alts=() + if ! compset -P '[kKmMpP]' && [[ -z $PREFIX ]]; then + alts+=( + "size-specifiers:size specifier:\ +((k\:kb m\:mb p\:512-byte\ blocks))") + fi + if ! compset -P '[-+]' && [[ -z $PREFIX ]]; then + alts+=("senses:sense:((-\:less\ than +\:more\ than))") + fi + alts+=('digits:digit: ') + _alternative $alts + return + fi + ;; + + ([oO]) + # complete/skip sort spec + if ! compset -P "?"; then + alts=( + "n:lexical order of name" + "L:size of file" + "l:number of hard links" + "a:last access time" + "m:last modification time" + "c:last inode change time" + "d:directory depth" + ) + _describe -t sort-specifiers "sort specifier" alts -Q -S '' + return + fi + ;; + + (\[) + # complete/skip range: check for closing bracket + if ! compset -P "(-|)[[:digit:]]##(,(-|)[[:digit:]]##|)]"; then + if compset -P "(-|)[[:digit:]]##,"; then + _message end of range + else + _message start of range + fi + return + fi + ;; + + (:) + # complete modifiers and don't stop completing them + _history_modifiers + return + ;; + esac +done + +case $state in + (qual) + local -a quals + quals=( + "/:directories" + "F:non-empty directories" + ".:plain files" + "@:symbolic links" + "=:sockets" + "p:name pipes (FIFOS)" + "*:executable plain files" + "%:device files" + "r:owner-readable" + "w:owner-writeable" + "x:owner-executable" + "A:group-readable" + "I:group-writeable" + "E:group-executable" + "R:world-readable" + "W:world-writeable" + "X:world-executable" + "s:setuid" + "S:setgid" + "t:sticky bit set" + "f:+ access rights" + "e:execute code" + "+:+ command name" + "d:+ device" + "l:+ link count" + "U:owned by EUID" + "G:owned by EGID" + "u:+ owning user" + "g:+ owning group" + "a:+ access time" + "m:+ modification time" + "c:+ inode change time" + "L:+ size" + "^:negate qualifiers" + "-:follow symlinks toggle" + "M:mark directories" + "T:mark types" + "N:use NULL_GLOB" + "D:glob dots" + "n:numeric glob sort" + "o:+ sort order, up" + "O:+ sort order, down" + "[:+ range of files" + "):end of qualifiers" + "\::modifier" + ) + _describe -t globquals "glob qualifier" quals -Q -S '' + ;; +esac diff --git a/Completion/Zsh/Type/_history_modifiers b/Completion/Zsh/Type/_history_modifiers new file mode 100644 index 000000000..085867159 --- /dev/null +++ b/Completion/Zsh/Type/_history_modifiers @@ -0,0 +1,84 @@ +#autoload + +# Complete history-style modifiers; the first : will have +# been matched and compset -p 1'd. +# The single argument is the type of context: +# h history +# q glob qualifier +# p parameter + +local -a list + +local type=$1 delim expl +integer global + +while true; do + if [[ -n $PREFIX ]]; then + local char=$PREFIX[1] + + global=0 + compset -p 1 + case $char in + ([hretpqQxlu\&]) + # single character modifiers + ;; + + (s) + # match delimiter string delimiter string delimiter + if [[ -z $PREFIX ]]; then + _delimiters modifier-s + return + fi + delim=$PREFIX[1] + compset -p 1 + if ! compset "[^$delim]#$delim[^$delim]#$delim"; then + if compset "[^$delim]#$delim"; then + _message original string + else + _message replacement string + fi + return + fi + ;; + + (g) + global=1 + continue + ;; + esac + + # modifier completely matched, see what's next. + compset -P : && continue + # if there's something other than colon next, bummer + [[ -n $PREFIX ]] && return 1 + + list=("\::modifier") + [[ $type = g ]] && list+=("):end of qualifiers") + # strictly we want a normal suffix if end of qualifiers + _describe -t delimiters "delimiter" list -Q -S '' + else + list=( + "s:substitute string" + "&:repeat substitution" + ) + if (( ! global )); then + list+=( + "g:globally apply s or &" + "h:head - strip trailing path element" + "t:tail - strip directories" + "r:root - strip suffix" + "e:leave only extension" + "Q:strip quotes" + "l:lower case all words" + "u:upper case all words" + ) + [[ $type = h ]] && list+=( + "p:print without executing" + "x:quote words, breaking on whitespace" + ) + [[ $type = [hp] ]] && list+=("q:quote to escape further substitutions") + fi + _describe -t modifiers "modifier" list -Q -S '' + return + fi +done diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 04fc6ecfa..c609991d6 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -1262,6 +1262,15 @@ This style is used by the tt(_list) completer function to decide if insertion of matches should be delayed unconditionally. The default is `true'. ) +kindex(delimiters, completion style) +item(tt(delimiters))( +This style is used when adding a delimiter for use with history +modifiers or glob qualifiers that have delimited arguments. It is +an array of preferred delimiters to add. Non-special characters are +preferred as the completion system may otherwise become confused. +The default list is tt(:), tt(+), tt(/), tt(-), tt(%). The list +may be empty to force a delimiter to be typed. +) kindex(disabled, completion style) item(tt(disabled))( If this is set to `true', the tt(_expand_alias) completer and bindable -- cgit 1.4.1