summaryrefslogtreecommitdiff
path: root/Functions/Completion/init
diff options
context:
space:
mode:
Diffstat (limited to 'Functions/Completion/init')
-rw-r--r--Functions/Completion/init253
1 files changed, 253 insertions, 0 deletions
diff --git a/Functions/Completion/init b/Functions/Completion/init
new file mode 100644
index 000000000..a40c5f61b
--- /dev/null
+++ b/Functions/Completion/init
@@ -0,0 +1,253 @@
+# 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