diff options
Diffstat (limited to 'Misc/new-completion-examples')
-rw-r--r-- | Misc/new-completion-examples | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/Misc/new-completion-examples b/Misc/new-completion-examples new file mode 100644 index 000000000..659679891 --- /dev/null +++ b/Misc/new-completion-examples @@ -0,0 +1,453 @@ +# Define a new widget behaving like `expand-or-complete' but calling the +# function `main-complete' to generate matches. + +zle -c my-comp expand-or-complete main-complete + +bindkey '\C-i' my-comp + + +# Below is a proposed main loop and the things it needs. + +# One associative array for normal completions and one for patterns. + +typeset -A comps + + +# These may be used to define completion handlers. First argument is the +# name of the function/variable containing the definition, the other +# arguments are the command names for which this definition should be used. +# With only one argument the function/variable-name __$1 is used. + +defcomp() { + local v + + if [[ $# -eq 1 ]] then + comps[$1]="__$1" + else + v="$1" + shift + for i; do + comps[$i]="$v" + done + fi +} + +defpatcomp() { + if [[ ${+patcomps} == 1 ]] then + patcomps=("$patcomps[@]" "$2 $1" ) + else + patcomps=( "$2 $1" ) + fi +} + + +# These can be used to easily save and restore the state of the special +# variables used by the completion code. + +alias compsave='local _opre _oipre _oargs _ocur;_opre="$PREFIX";_oipre="$IPREFIX";_oargs=( "$@" );_ocur="$CURRENT"' +alias compreset='PREFIX="$_opre";IPREFIX="$_oipre";argv=( "$_oargs[@]" );CURRENT="$_ocur"' + +# This is an easy way to get completion for sub-commands. + +alias compsub='do-complete "$@" || return 1' + +# This searches $1 in the array for normal completions and calls the result. + +compalso() { + 1="$comps[$1]" + [[ -z "$1" ]] || call-complete "$@" +} + +# This generates matches. The first argument is something we got from one +# of the associative arrays above. This is expected to be either the name +# of a variable in which case we use its value as arguments to complist, +# or it is the name of a function in which case we call this function with +# the arguments from the command line as its arguments. + +call-complete() { + local var + + eval var\=\$\{\+$1\} + if [[ "$var" == 0 ]] then + "$@" + else + eval complist \$\{${1}\[\@\]\} + fi +} + +# The main loop of the competion code. This is what is called when TAB is +# pressed. The completion code gives us the special variables and the +# arguments from the command line are gives as positional parameters. + +main-complete() { + emulate -R zsh + local comp + setopt localoptions nullglob rcexpandparam globdots + unsetopt markdirs globsubst shwordsplit nounset + + # An entry for `--first--' is the replacement for `compctl -T' + # The `|| return 1' is used throughout: if a function producing matches + # returns non-zero this is interpreted as `do not try to produce more matches' + # (this is the replacement for `compctl -t'). + + comp="$comps[--first--]" + [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1 + + # For arguments we use the `do-complete' function below called via the + # convenience alias `compsub'. + + if [[ $CONTEXT == argument || $CONTEXT == command ]] then + compsub + else + # Let's see if we have a special completion definition for the other + # possible contexts. + + comp='' + + case $CONTEXT in + redirect) comp="$comps[--redir--]";; + math) comp="$comps[--math--]";; + subscript) comp="$comps[--subscr--]";; + value) comp="$comps[--value--]";; + condition) comp="$comps[--cond--]";; + esac + + # If not, we use default completion, if any. + + [[ -z "$comp" ]] && comp="$comps[--default--]" + [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1 + fi +} + +# This does completion for a command (in command position and for the +# arguments). + +do-complete() { + local comp cmd1 cmd2 pat val + + # Completing in command position? If not we set up `cmd1' and `cmd2' as + # two strings we have search in the completion definition arrays (e.g. + # a path and the last path name component). + + if [[ $CONTEXT == command ]] then + comp="$comps[--command--]" + [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1 + return 0 + elif [[ "$COMMAND[1]" == '=' ]] then + eval cmd1\=$COMMAND + cmd2="$COMMAND[2,-1]" + elif [[ "$COMMAND" == */* ]] then + cmd1="$COMMAND" + cmd2="${COMMAND:t}" + else + cmd1="$COMMAND" + eval cmd2=$(whence -p $COMMAND) + fi + + # See if there are any matching pattern completions. + + for i in "$patcomps[@]"; do + pat="${i% *}" + val="${i#* }" + if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]] then + call-complete "$val" "$@" || return 1 + fi + done + + # Now look up the two names in the normal completion array. + + comp="${comps[$cmd1]:-$comps[$cmd2]}" + + # And generate the matches, probably using default completion. + + [[ -z "$comp" ]] && comp="$comps[--default--]" + [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1 +} + +# Do sub-completion for pre-command modifiers. + +defcomp __precmd - noglob nocorrect exec command builtin +__precmd() { + COMMAND="$1" + shift + (( CURRENT-- )) + if [[ CURRENT -eq 0 ]] then + CONTEXT=command + else + CONTEXT=argument + fi + compsub +} + +# Utility function for in-path completion. +# First argument should be an complist-option (e.g. -f, -/, -g). The other +# arguments should be glob patterns, one per argument. +# E.g.: files -g '*.tex' '*.texi' +# This is intended as a replacement for `complist -f', `complist -/', and +# `complist -g ...' (but don't use it with other options). +# This function behaves as if you have a matcher definition like: +# compctl -M 'r:|[-.,_/]=* r:|=* m:{a-z}={A-Z} m:-=_ m:.=,' +# so you may want to modify this. + +pfiles() { + local nm str pa pre epre a b c s rest + + setopt localoptions nullglob rcexpandparam globdots extendedglob + unsetopt markdirs globsubst shwordsplit nounset + + nm=$NMATCHES + if [[ $# -eq 0 ]] then + complist -f + elif [[ "$1" = -g ]] then + complist -g "$argv[2,-1]" + shift + else + complist $1 + shift + fi + [[ -nmatches nm ]] || return + + str="$PREFIX*$SUFFIX" + + [[ -z "$1" ]] && 1='*' + if [[ $str[1] = \~ ]] then + pre="${str%%/*}/" + eval epre\=$pre + str="${str#*/}" + pa='' + else + pre='' + epre='' + if [[ $str[1] = / ]] then + str="$str[2,-1]" + pa='/' + else + pa='' + fi + fi + str="$str:gs/,/*,/:gs/_/*_/:gs./.*/.:gs/-/*[-_]/:gs/./*[.,]/:gs-*[.,]*[.,]*/-../-:gs.**.*." + while [[ "$str" = */* ]] do + rest="${str#*/}" + a="${epre}${pa}(#l)${str%%/*}(-/)" + a=( $~a ) + if [[ $#a -eq 0 ]] then + return + elif [[ $#a -gt 1 ]] then + c=() + s=( $rest$@ ) + s=( "${(@)s:gs.**.*.}" ) + for i in $a; do + b=( $~i/(#l)$~s ) + eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \) + [[ $#b -ne 0 ]] && c=( $c $i ) + done + if [[ $#c -eq 0 ]] then + return + elif [[ $#c -ne 1 ]] then + a="$epre$pa" + c=( $~c/(#l)$~s ) + eval c\=\( \$\{c:/\*\(${(j:|:)fignore}\)\} \) + c=( ${c#$a} ) + for i in $c; do + compadd -p "$pre$pa" -W "$a" -s "/${i#*/}" -f "${i%%/*}" + done + return + fi + a=( "$c[1]" ) + fi + a="$a[1]" + pa="$pa${a##*/}/" + str="$rest" + done + a="$epre$pa" + s=( $str$@ ) + s=( "${(@)s:gs.**.*.}" ) + b=( $~a(#l)$~s ) + eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \) + compadd -p "$pre$pa" -W "$epre$pa" -f ${b#$a} +} + +# Utility function for completing files of a given type or any file. +# In many cases you will want to call this one instead of pfiles(). + +files() { + local nm + + nm=$NMATCHES + pfiles "$@" + + [[ $# -ne 0 && -nmatches nm ]] && pfiles +} + +# Simple default, command, and math completion defined with variables. + +defcomp __default --default-- +__default() { + files +} + +defcomp __command --command-- +__command=( -c ) + +defcomp __math --math-- +__math=( -v ) + +defcomp __subscr --subscr-- +__subscr() { + compalso --math-- "$@" + # ...probably other stuff +} + +# A simple pattern completion, just as an example. + +defpatcomp __x_options '*/X11/*' +__x_options() { + complist -J options -k '(-display -name -xrm)' +} + +# A better example: completion for `find'. + +defcomp find +__find() { + compsave + + if [[ -mbetween -(ok|exec) \\\; ]] then + compsub + elif [[ -iprefix - ]] then + complist -s 'daystart {max,min,}depth follow noleaf version xdev \ + {a,c,}newer {a,c,m}{min,time} empty false {fs,x,}type gid inum links \ + {i,}{l,}name {no,}{user,group} path perm regex size true uid used \ + exec {f,}print{f,0,} ok prune ls' + compreset + elif [[ -position 1 ]] then + complist -g '. ..' + files -g '(-/)' + elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]] then + files + elif [[ -current -1 -fstype ]] then + complist -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)' + elif [[ -current -1 -group ]] then + complist -k groups + elif [[ -current -1 -user ]] then + complist -u + fi +} + +# Various completions... + +defcomp __gunzip gunzip zcat +__gunzip() { + files -g '*.[gG][z]' +} + +defcomp gzip +__gzip() { + files -g '*~*.[gG][zZ]' +} + +defcomp xfig +__xfig() { + files -g '*.fig' +} + +defcomp __make make gmake +__make() { + complist -s "\$(awk '/^[a-zA-Z0-9][^/ ]+:/ {print \$1}' FS=: [mM]akefile)" +} + +defcomp __ps gs ghostview gview psnup psselect pswrap pstops pstruct lpr +__ps() { + files -g '*([pP][sS]|eps)' +} + +defcomp __which which whence +__which=( -caF ) + +defcomp __rlogin rlogin rsh ssh +__rlogin() { + if [[ -position 1 ]] then + complist -k hosts + elif [[ -position 2 ]] then + complist -k '(-l)' + elif [[ -position 3 && -word 1 artus ]] then + complist -k '(puck root)' + fi +} + +defcomp __dvi xdvi dvips dvibook dviconcat dvicopy dvidvi dviselect dvitodvi dvitype +__dvi() { + files -g '*.(dvi|DVI)' +} + +defcomp __dirs rmdir df du dircmp cd +__dirs() { + files -/ '*(-/)' +} + +defcomp __jobs fg bg jobs +__jobs=(-j -P '%?') + +defcomp kill +__kill() { + if [[ -iprefix '-' ]] then + complist -k signals + else + complist -P '%?' -j + fi +} + +defcomp __uncompress uncompress zmore +__uncompress() { + files -g '*.Z' +} + +defcomp compress +__compress() { + files -g '*~*.Z' +} + +defcomp __tex tex latex glatex slitex gslitex +__tex() { + files -g '*.(tex|TEX|texinfo|texi)' +} + +defcomp __options setopt unsetopt +__options=(-M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o) + +defcomp __funcs unfunction +__funcs=(-F) + +defcomp __aliases unalias +__aliases=(-a) + +defcomp __vars unset +__vars=(-v) + +defcomp __enabled disable +__enabled=(-FBwa) + +defcomp __disabled enable +__disabled=(-dFBwa) + +defcomp __pdf acroread +__pdf() { + files -g '*.(pdf|PDF)' +} + +defcomp tar +__tar() { + local nm tf + compsave + + tf="$2" + nm=$NMATCHES + if [[ ( -mword 1 *t*f* || -mword 1 *x*f* ) && -position 3 100000 ]] then + complist -k "( $(tar tf $tf) )" + compreset + elif [[ -mword 1 *c*f* && -position 3 100000 ]] then + files + compreset + elif [[ -mcurrent -1 *f* && -position 2 ]] then + files -g '*.(tar|TAR)' + fi +} |