1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-07-25 21:31:03 +02:00
zsh/Functions/Completion/init
1999-04-15 18:15:04 +00:00

253 lines
7.7 KiB
Text

# Initialisation for new style completion. This mainly contains some helper
# function and aliases. Everything else is split into different files in this
# 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).
# The first line of these files will be read and has to say what should be
# done with its contents:
#
# `#function <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>'
# 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> ... ]
# 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,
# expand-or-complete, expand-or-complete-prefix, list-choices,
# menu-complete, menu-expand-or-complete, or reverse-menu-complete).
# This creates a widget behaving like <style> so that the
# completions are chosen as given in the the rest of the file,
# 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'
# 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.
# 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'.
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.
# If given the `-a' option, the function is defined as being autoloaded.
defcomp() {
local name autol=''
if [[ "$1" = -a ]]; then
shift
autol=yes
fi
if [[ $# -eq 1 ]]; then
comps[$1]="__$1"
[[ -z "$autol" ]] || autoload "__$1"
else
name="$1"
shift
for i; do
comps[$i]="$name"
done
[[ -z "$autol" ]] || autoload "$name"
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.
defpatcomp() {
if [[ "$1" = -a ]]; then
shift
autoload "$1"
fi
if (( $+patcomps )) then
patcomps=("$patcomps[@]" "$2 $1" )
else
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
# remaining arguments are used as key sequences to bind the widget.
# Typing that key sequence will complete the word the cursor is on
# according to the completion definition given and will behave as if the
# built-in completion widget was used.
defkeycomp() {
local name
if [[ "$1" = -a ]]; then
shift
autoload "$1"
name="$1"
elif [[ "${1[1]}" = ' ' ]]; then
name="${1:t}"
else
name="$1"
fi
keycomps[$name]="$1"
shift
zle -C "$name" "$1" __main_key_complete
shift
while (( $# )); do
bindkey "$1" "$name"
shift
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() {
local tmp
tmp="$comps[$1]"
[[ -z "$tmp" ]] || callcomplete comps "$1" "$@"
}
# 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
# Get the definition from the array.
eval "def=\$${1}[${2}]"
# 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.
file="$def[2,-1]"
builtin . "$file"
def="${file:t}"
eval "${1}[${2}]=$def"
fi
# Get rid of the array-name and -index.
shift 2
if [[ ${(P)+def} -eq 1 ]]; then
# It is a parameter name, call complist directly.
complist "${(@P)def}"
else
# Otherwise it's a function name, call this function.
"$def" "$@"
fi
}
# 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