From e17fc5079394ce0c30dc0573676983e6f4a0a5bc Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 7 Mar 2006 12:50:56 +0000 Subject: 22328, modified: add -o option to compadd add _list_files helper to handle new file-list style for _path_files --- ChangeLog | 8 +++++ Completion/Unix/Type/_list_files | 66 ++++++++++++++++++++++++++++++++++++++++ Completion/Unix/Type/_path_files | 39 +++++++++++++++++++----- Doc/Zsh/compsys.yo | 30 ++++++++++++++++++ Doc/Zsh/compwid.yo | 8 ++++- Src/Zle/comp.h | 1 + Src/Zle/compcore.c | 4 +-- Src/Zle/complete.c | 3 ++ 8 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 Completion/Unix/Type/_list_files diff --git a/ChangeLog b/ChangeLog index 5a551a7a1..a1a7115fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2006-03-07 Peter Stephenson + * 22328, modified: Completion/Unix/Type/_list_files, + Completion/Unix/Type/_path_files, Doc/Zsh/compsys.yo, + Doc/Zsh/compwid.yo, Src/Zle/comp.h, Src/Zle/compcore.c, + Src/Zle/complete.c: Option -o to compadd uses match + strings rather than display strings from -d for sorting; + _path_files uses _list_files to handle file-list style + which allows long format file lists. + * unposted: Config/version.mk: belatedly update version to 4.3.2-dev-1 to avoid clash with released version. diff --git a/Completion/Unix/Type/_list_files b/Completion/Unix/Type/_list_files new file mode 100644 index 000000000..2166ac6cc --- /dev/null +++ b/Completion/Unix/Type/_list_files @@ -0,0 +1,66 @@ +#autoload + +# Helper function for _path_files to handle the file-list style. + +# arguments: +# name of parameter containing file matches +# directory prefix +# Sets array listfiles to the display strings and the array +# listopts appropriately to be added to the compadd command line. + +local stat f elt what +local -a stylevals +integer ok + +listfiles=() +listopts=() + +zmodload -i zsh/stat 2>/dev/null || return 1 + +zstyle -a ":completion:${curcontext}:" file-list stylevals || return 1 + +# TODO: more flexible way of handling the following? e.g. use $compstate? +case $WIDGETSTYLE in + (*complete*) + what=insert + ;; + + (*) + what=list + ;; +esac + +for elt in $stylevals; do + case $elt in + (*($what|all|true|1|yes)*=<->) + # use long format if no more than the given number of matches + (( ${(P)#1} <= ${elt##*=} )) && (( ok = 1 )) + break + ;; + + (*($what|all|true|1|yes)[^=]#) + # always use long format + (( ok = 1 )) + break + ;; + esac +done + +(( ok )) || return 1 + +for f in ${(P)1}; do + if [[ ! -e "${2:+$2/}$f" ]]; then + listfiles+=("${2:+$2/}$f") + continue + fi + + # Borrowed from Functions/Example/zls + stat -s -H stat -F "%b %e %H:%M" - "${2:+$2/}$f" >/dev/null 2>&1 + + listfiles+=("$stat[mode] ${(l:3:)stat[nlink]} ${(r:8:)stat[uid]} \ + ${(r:8:)stat[gid]} ${(l:8:)stat[size]} $stat[mtime] $f") +done + +(( ${#listfiles} )) && listopts=(-d listfiles -l -o) + +return 0 diff --git a/Completion/Unix/Type/_path_files b/Completion/Unix/Type/_path_files index aae248bf5..f20a941c0 100644 --- a/Completion/Unix/Type/_path_files +++ b/Completion/Unix/Type/_path_files @@ -7,6 +7,7 @@ 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 listfiles listopts tmpdisp typeset -U prepaths exppaths @@ -539,46 +540,65 @@ for prepath in "$prepaths[@]"; do ( -n "$_comp_correct" || -z "$compstate[pattern_match]" || "$SUFFIX" != */* || "${SUFFIX#*/}" = (|*[^\\])[][*?#~^\|\<\>]* ) ]] }; then + # We have not been told to insert the match, so we are + # listing, or something. (( tmp4 )) && zstyle -t ":completion:${curcontext}:paths" ambiguous && compstate[to_end]= if [[ "$tmp3" = */* ]]; then if [[ -z "$listsfx" || "$tmp3" != */?* ]]; then + # I think this means we are expanding some directory + # back up the path. + tmp1=("${(@)tmp1%%/*}") + _list_files tmp1 "$prepath$realpath$testpath" compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \ -W "$prepath$realpath$testpath" \ "$pfxsfx[@]" -M "r:|/=* r:|=*" \ - - "${(@)tmp1%%/*}" + $listopts \ + -a tmp1 else + # Same with a non-empty suffix + tmp1=("${(@)^tmp1%%/*}/${tmp3#*/}") + _list_files tmp1 "$prepath$realpath$testpath" compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ -W "$prepath$realpath$testpath" \ "$pfxsfx[@]" -M "r:|/=* r:|=*" \ - - "${(@)^tmp1%%/*}/${tmp3#*/}" + $listopts \ + -a tmp1 fi else + _list_files tmp1 "$prepath$realpath$testpath" compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ -W "$prepath$realpath$testpath" \ "$pfxsfx[@]" -M "r:|/=* r:|=*" \ + $listopts \ -a tmp1 fi else + # We are inserting the match into the command line. if [[ "$tmp3" = */* ]]; then tmp4=( -Qf "$mopts[@]" -p "$linepath$tmp2" -W "$prepath$realpath$testpath" "$pfxsfx[@]" -M "r:|/=* r:|=*" ) if [[ -z "$listsfx" ]]; then for i in "$tmp1[@]"; do - compadd "$tmp4[@]" -s "/${i#*/}" - "${i%%/*}" + tmpdisp=("${i%%/*}") + _list_files tmpdisp "$prepath$realpath$testpath" + compadd "$tmp4[@]" -s "/${i#*/}" $listopts - "$tmpdisp" done else [[ -n "$compstate[pattern_match]" ]] && SUFFIX="${SUFFIX:s./.*/}*" for i in "$tmp1[@]"; do - compadd "$tmp4[@]" - "$i" + _list_files i "$prepath$realpath$testpath" + compadd "$tmp4[@]" $listopts - "$i" done fi else + _list_files tmp1 "$prepath$realpath$testpath" compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \ -W "$prepath$realpath$testpath" \ "$pfxsfx[@]" -M "r:|/=* r:|=*" \ + $listopts \ -a tmp1 fi fi @@ -642,9 +662,10 @@ for prepath in "$prepaths[@]"; do fi compquote tmp4 tmp2 tmp1 for i in "$tmp1[@]"; do + _list_files tmp2 "$prepath$realpath${mid%/*/}" compadd -Qf "$mopts[@]" -p "$linepath$tmp3/" -s "/$tmp4$i" \ -W "$prepath$realpath${mid%/*/}/" \ - "$pfxsfx[@]" -M "r:|/=* r:|=*" - "$tmp2" + "$pfxsfx[@]" -M "r:|/=* r:|=*" $listopts - "$tmp2" done else if [[ "$osuf" = */* ]]; then @@ -665,11 +686,15 @@ for prepath in "$prepaths[@]"; do fi if [[ -z "$_comp_correct" && -n "$compstate[pattern_match]" && "${PREFIX#\~}$SUFFIX" = (|*[^\\])[][*?#~^\|\<\>]* ]]; then + tmp1=("$linepath$tmp4${(@)^tmp1}") + _list_files tmp1 "$prepath$realpath" compadd -Qf -W "$prepath$realpath" "$pfxsfx[@]" "$mopts[@]" \ - -M "r:|/=* r:|=*" - "$linepath$tmp4${(@)^tmp1}" + -M "r:|/=* r:|=*" $listopts -a tmp1 else + # Not a pattern match + _list_files tmp1 "$prepath$realpath$testpath" compadd -Qf -p "$linepath$tmp4" -W "$prepath$realpath$testpath" \ - "$pfxsfx[@]" "$mopts[@]" -M "r:|/=* r:|=*" -a tmp1 + "$pfxsfx[@]" "$mopts[@]" -M "r:|/=* r:|=*" $listopts -a tmp1 fi fi fi diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 11c50cf61..5c844e133 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -1263,6 +1263,36 @@ given, the name will only be completed if parameters of that type are required in the particular context. Names for which no type is specified will always be completed. ) +kindex(file-list, completion style) +item(tt(file-list))( +This style controls whether files completed using the standard builtin +mechanism are to be listed with a long list similar to tt(ls -l) +(although note that this feature actually uses the shell module +tt(zsh/stat) for file information). + +The style may either be set to a true value (or `tt(all)'), or +one of the values `tt(insert)' or `tt(list)', indicating that files +are to be listed in long format in all circumstances, or when +attempting to insert a file name, or when listing file names +without attempting to insert one. + +More generally, the value may be an array of any of the above values, +optionally followed by tt(=)var(num). If var(num) is present it +gives the maximum number of matches for which long listing style +will be used. For example, + +example(zstyle ':completion:*' file-list list=20 insert=10) + +specifies that long format will be used when listing up to 20 files +or inserting a file with up to 10 matches (assuming a listing +is to be shown at all, for example on an ambiguous completion), else short +format will be used. + +example(zstyle -e ':completion:*' file-list '(( ${+NUMERIC} )) && reply=(true)') + +specifies that long format will be used any time a numeric argument is +supplied, else short format. +) kindex(file-patterns, completion style) item(tt(file-patterns))( This is used by the standard function for completing filenames, diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index bdbdd99da..8ffc96a2e 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -436,7 +436,7 @@ sect(Builtin Commands) startitem() findex(compadd) cindex(completion widgets, adding specified matches) -xitem(tt(compadd) [ tt(-akqQfenUl12C) ] [ tt(-F) var(array) ]) +xitem(tt(compadd) [ tt(-akqQfenUld12C) ] [ tt(-F) var(array) ]) xitem([ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ]) xitem([ tt(-p) var(hidden-prefix) ] [ tt(-s) var(hidden-suffix) ]) xitem([ tt(-i) var(ignored-prefix) ] [ tt(-I) var(ignored-suffix) ]) @@ -530,6 +530,12 @@ 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, not arrayed in columns. ) +item(tt(-o))( +This option only has an effect if used together with the tt(-d) +option. If it is 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). +) item(tt(-J) var(name))( Gives the name of the group of matches the words should be stored in. ) diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 5e25cdeb6..e88f8b927 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -131,6 +131,7 @@ struct cmatch { #define CMF_FMULT (1<<12) /* first of multiple equal strings */ #define CMF_ALL (1<<13) /* a match representing all other matches */ #define CMF_DUMMY (1<<14) /* unselectable dummy match */ +#define CMF_MORDER (1<<15) /* order by matches, not display strings */ /* Stuff for completion matcher control. */ diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 1caad5484..008f49185 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -2735,7 +2735,7 @@ addexpl(int always) static int matchcmp(Cmatch *a, Cmatch *b) { - if ((*a)->disp) { + if ((*a)->disp && !((*a)->flags & CMF_MORDER)) { if ((*b)->disp) { if ((*a)->flags & CMF_DISPLINE) { if ((*b)->flags & CMF_DISPLINE) @@ -2751,7 +2751,7 @@ matchcmp(Cmatch *a, Cmatch *b) } return -1; } - if ((*b)->disp) + if ((*b)->disp && !((*b)->flags & CMF_MORDER)) return 1; return strbpcmp(&((*a)->str), &((*b)->str)); diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index e246e2b8a..c70c8c191 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -569,6 +569,9 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) case 'l': dat.flags |= CMF_DISPLINE; break; + case 'o': + dat.flags |= CMF_MORDER; + break; case 'E': if (p[1]) { dat.dummies = atoi(p + 1); -- cgit 1.4.1