diff options
Diffstat (limited to 'Functions/Completion/init')
-rw-r--r-- | Functions/Completion/init | 246 |
1 files changed, 107 insertions, 139 deletions
diff --git a/Functions/Completion/init b/Functions/Completion/init index a40c5f61b..35e7f6a3c 100644 --- a/Functions/Completion/init +++ b/Functions/Completion/init @@ -3,34 +3,22 @@ # directory that will automatically be made autoloaded (see the end of this # file). # The names of the files that will be considered for autoloading have to -# start with two underscores (like `__setopt). +# start with a underscores (like `_setopt). # The first line of these files will be read and has to say what should be # done with its contents: # -# `#function <names ...>' +# `#defcomp <names ...>' # if the first line looks like this, the file is # autoloaded as a function and that function will # be called to generate the matches when completing # for one of the commands whose <name> is given # -# `#array <names ...>' -# with a first line like this, the filename is taken as -# the name of an array; when trying to generate matches -# for the command <name>, the file will be sourced and -# should define this array, the builtin `complist' will -# then be called with the elements of this array as its -# arguments; this is intended for simple definitions -# for which you don't need a shell function -# -# `#pattern-function <pattern>' +# `#defpatcomp <pattern>' # this defines a function that should be called to generate # matches for commands whose name matches <pattern>; note # that only one pattern may be given # -# `#pattern-array <pattern>' -# like `#pattern-function' but defining an array -# -# `#key-function <style> [ <key-sequence> ... ] +# `#defkeycomp <style> [ <key-sequence> ... ] # this is used to bind special completions to all the given # <key-sequence>(s). The <style> is the name of one of the built-in # completion widgets (complete-word, delete-char-or-list, @@ -41,45 +29,47 @@ # rather than by the context. The widget has the same name as # the autoload file and can be bound using bindkey in the normal way. # -# `#key-array <style> [ <key-sequence> ... ] -# like `#key-function', but defining an array instead -# -# `#helper' +# `#autoload' # this is for helper functions that are not used to # generate matches, but should automatically be loaded # when they are called # # Note that no white space is allowed between the `#' and the rest of # the string. +# +# See the file `dump' for how to speed up initialiation. +# If we got the `-d'-flag, we will automatically dump the new state (at +# the end). -# An associative array for completions definitions. The keys of the entries -# are the names of the command, the values are names of functions or variables -# that are to be used to generate the matches. -# Pattern completions will be stored in an normal array named `patcomps'. -# Completion definitions bound directly to keys are stored in an assoc array -# named `keycomps'. +if [[ "$1" = -d ]]; then + _i_autodump=1 +else + _i_autodump=0 +fi + +# The associative array containing the definitions for the commands. +# Definitions for patterns will be stored in the normal array `patcomps'. typeset -A comps -typeset -A keycomps # This may be used to define completion handlers. The first argument is the -# name of the function or 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. +# name of the function 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. # If given the `-a' option, the function is defined as being autoloaded. defcomp() { - local name autol='' + local name if [[ "$1" = -a ]]; then shift autol=yes fi if [[ $# -eq 1 ]]; then - comps[$1]="__$1" - [[ -z "$autol" ]] || autoload "__$1" + comps[$1]="_$1" + [[ -z "$autol" ]] || autoload "_$1" else name="$1" shift @@ -90,10 +80,9 @@ defcomp() { fi } - # Almost like `defcomp', but this always gets two arguments: the name of a -# variable or function describing what should be completed and the pattern -# that will be compared to the command names for which completion is attempted. +# function describing what should be completed and the pattern that will be +# compared to the command names for which completion is attempted. defpatcomp() { if [[ "$1" = -a ]]; then @@ -101,13 +90,12 @@ defpatcomp() { autoload "$1" fi if (( $+patcomps )) then - patcomps=("$patcomps[@]" "$2 $1" ) + patcomps=("$patcomps[@]" "$2 $1") else - patcomps=( "$2 $1" ) + patcomps=("$2 $1") fi } - # This is used to define completion handlers directly bound to keys. The # first argument is as for `defcomp', giving the handler. The second # argument is the name of one of the built-in completion widgets. Any @@ -122,15 +110,10 @@ defkeycomp() { if [[ "$1" = -a ]]; then shift autoload "$1" - name="$1" - elif [[ "${1[1]}" = ' ' ]]; then - name="${1:t}" - else - name="$1" fi - keycomps[$name]="$1" + name="$1" shift - zle -C "$name" "$1" __main_key_complete + zle -C "$name" "$1" "$name" shift while (( $# )); do bindkey "$1" "$name" @@ -138,116 +121,101 @@ defkeycomp() { done } -# These can be used to easily save and restore the state of the special -# variables used by the completion code. - -alias compsave='local _oprefix _oiprefix _oargv _ocurrent; \ - _oprefix="$PREFIX"; \ - _oiprefix="$IPREFIX"; \ - _oargv=( "$@" ); \ - _ocurrent="$CURRENT"' -alias compreset='PREFIX="$_oprefix"; \ - IPREFIX="$_oiprefix"; \ - argv=( "$_oargv[@]" ); \ - CURRENT="$_ocur"' - - -# This is an easy way to get completion for sub-commands. - -alias compsub='__normal "$@" || return 1' - - # This searches $1 in the array for normal completions and calls the result. -compalso() { +_compalso() { local tmp tmp="$comps[$1]" - [[ -z "$tmp" ]] || callcomplete comps "$1" "$@" + [[ -z "$tmp" ]] || "$tmp" "$@" } +# These can be used to easily save and restore the state of the special +# variables used by the completion code. -# This generates matches. The first argument is the name of one of the -# arrays containing completion definitions. The second argument is the index -# into this array. The other arguments are the positional parameters to give -# to the completion function (containing the arguments from the command line). - -callcomplete() { - local file def +alias _compsave='local _oprefix$_level _oiprefix$_level _oargv$_level _ocurrent$_level _ocommand$_level _ocontext$_level; \ + eval "_oprefix${_level}=\"\$PREFIX\"; \ + _oiprefix${_level}=\"\$IPREFIX\"; \ + _oargv${_level}=( \"\$@\" ); \ + _ocurrent${_level}=\"\$CURRENT\"; \ + _ocommand${_level}=\"\$COMMAND\"; \ + _ocontext${_level}=\"\$CONTEXT\""' +alias _compreset='eval "PREFIX=\"\$_oprefix${_level}\"; \ + IPREFIX=\"\$_oiprefix${_level}\"; \ + argv=( \"\$_oargv${_level}[@]\" ); \ + CURRENT=\"\$_ocur${_level}\"; \ + COMMAND=\"\$_ocommand${_level}\"; \ + CONTEXT=\"\$_ocontext${_level}\""' - # Get the definition from the array. +# These can be used to build tests that modify the special parameters +# without having to reset them by hand. - eval "def=\$${1}[${2}]" +alias _if='(( $+_level )) || local _level=0; (( _level++ )); _compsave; if' +alias _elif='_compreset; elif' +alias _else='_compreset; else' +alias _fi='_compreset; fi; unset _oprefix$_level _oiprefix$_level _oargv$_level _ocurrent$_level _ocommand$_level _ocontext$_level; (( _level-- ))' - # If the definition starts with a space then this means that we should - # source a file to get the definition for an array. - if [[ "$def[1]" = ' ' ]]; then - # The definition starts with a space, so source the file and change - # the definition. +# Now we automatically make the definition files autoloaded. - file="$def[2,-1]" - builtin . "$file" - def="${file:t}" - eval "${1}[${2}]=$def" - fi +# First we get the name of a dump file if this will be used. - # Get rid of the array-name and -index. +: ${COMPDUMP:=$0.dump} - shift 2 - if [[ ${(P)+def} -eq 1 ]]; then - # It is a parameter name, call complist directly. +_i_files=( ${^~fpath}/_*~*~ ) +_i_initname=$0 +_i_done='' - complist "${(@P)def}" - else - # Otherwise it's a function name, call this function. +# If we have a dump file, load it. - "$def" "$@" +if [[ -f "$COMPDUMP" ]]; then + read -rA _i_line < "$COMPDUMP" + if [[ _i_autodump -eq 1 || $_i_line[2] -eq $#_i_files ]]; then + builtin . "$COMPDUMP" + _i_done=yes fi -} + unset _i_line +fi +if [[ -z "$_i_done" ]]; then + + for _i_dir in $fpath; do + [[ $_i_dir = . ]] && continue + for _i_file in $_i_dir/_*~*~(N); do + read -rA _i_line < $_i_file + _i_tag=$_i_line[1] + shift _i_line + if [[ $_i_tag = '#defcomp' ]]; then + defcomp -a ${_i_file:t} "${_i_line[@]}" + elif [[ $_i_tag = '#defpatcomp' ]]; then + defpatcomp -a "${_i_file:t}" "${_i_line[@]}" + elif [[ $_i_tag = '#defkeycomp' ]]; then + defkeycomp -a "${_i_file:t}" "${_i_line[@]}" + elif [[ $_i_tag = '#autoload' ]]; then + autoload ${_i_file:t} + fi + done + done + + bindkey | + while read -rA _i_line; do + if [[ "$_i_line[2]" = complete-word || + "$_i_line[2]" = delete-char-or-list || + "$_i_line[2]" = expand-or-complete || + "$_i_line[2]" = expand-or-complete-prefix || + "$_i_line[2]" = list-choices || + "$_i_line[2]" = menu-complete || + "$_i_line[2]" = menu-expand-or-complete || + "$_i_line[2]" = reverse-menu-complete ]]; then + zle -C _complete_$_i_line[2] $_i_line[2] _main_complete + bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2] + fi + done + unset _i_dir _i_line _i_file _i_tag -# Now we make the files automatically autoloaded. - -local dir file line func - -for dir in $fpath; do - [[ $dir = . ]] && continue - for file in $dir/__*~*~(N); do - read -rA line < $file - func=$line[1] - shift line - if [[ $func = '#function' ]]; then - defcomp -a ${file:t} "${line[@]}" - elif [[ $func = '#array' ]]; then - defcomp " $file" "${line[@]}" - elif [[ $func = '#pattern-function' ]]; then - defpatcomp -a ${file:t} "${line[@]}" - elif [[ $func = '#pattern-array' ]]; then - defcomp " $file" "${line[@]}" - elif [[ $func = '#key-function' ]]; then - defkeycomp -a "${file:t}" "${line[@]}" - elif [[ $func = '#key-array' ]]; then - defkeycomp " $file" "${line[@]}" - elif [[ $func = '#helper' ]]; then - autoload ${file:t} - fi - done -done - - -# Finally we make all this be called by changing the key bindings. - -bindkey | while read -A line; do - if [[ "$line[2]" = complete-word || - "$line[2]" = delete-char-or-list || - "$line[2]" = expand-or-complete || - "$line[2]" = expand-or-complete-prefix || - "$line[2]" = list-choices || - "$line[2]" = menu-complete || - "$line[2]" = menu-expand-or-complete || - "$line[2]" = reverse-menu-complete ]]; then - zle -C __complete_$line[2] $line[2] __main_complete - bindkey "${line[1][2,-2]}" __complete_$line[2] - fi - done + # if autodumping was requested, do it now. + + (( _i_autodump )) && builtin . ${_i_initname:h}/dump +fi + +unset _i_files _i_initname _i_done _i_autodump |