diff options
Diffstat (limited to 'Functions/Zle')
-rw-r--r-- | Functions/Zle/add-zle-hook-widget | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/Functions/Zle/add-zle-hook-widget b/Functions/Zle/add-zle-hook-widget new file mode 100644 index 000000000..eeb0191f0 --- /dev/null +++ b/Functions/Zle/add-zle-hook-widget @@ -0,0 +1,140 @@ +# Add to HOOK the given WIDGET +# +# HOOK is one of isearch-exit, isearch-update, line-pre-redraw, line-init, +# line-finish, history-line-set, keymap-select (the zle- prefix is not +# required). +# +# WIDGET may be of the form INDEX:NAME in which case the INDEX determines +# the order in which the widget executes relative to other hook widgets. +# +# With -d, remove the widget from the hook instead; delete the hook +# variable if it is empty. +# +# -D behaves like -d, but pattern characters are active in the +# widget name, so any matching widget will be deleted from the hook. +# +# Without -d, if the WIDGET is not already defined, a function having the +# same name is marked for autoload; -U is passed down to autoload if that +# is given, as are -z and -k. (This is harmless if the function is +# already defined.) The WIDGET is then created with zle -N. + +emulate -L zsh + +# Setup - create the base functions for hook widgets that call the others + +zmodload zsh/parameter || { + print -u2 "Need parameter module for zle hooks" + return 1 +} + +local -a hooktypes=( isearch-exit isearch-update + line-pre-redraw line-init line-finish + history-line-set keymap-select ) +# Stash in zstyle to make it global +zstyle zle-hook types $hooktypes + +for hook in $hooktypes +do + function zle-$hook { + local -a hook_widgets + local hook + # Values of these styles look like number:name + # and we run them in number order + # $funcstack is more reliable than $0 + # Also, ksh_arrays is annoying + emulate zsh -c 'zstyle -a $funcstack[2] widgets hook_widgets' + for hook in "${@${(@on)hook_widgets}#*:}" + do + zle "$hook" -Nw || return + done + return 0 + } +done + +# Redefine ourself with the setup left out + +function add-zle-hook-widget { + local -a hooktypes + zstyle -a zle-hook types hooktypes + + # This part copied from add-zsh-hook + local usage="Usage: $0 hook widgetname\nValid hooks are:\n $hooktypes" + + local opt + local -a autoopts + integer del list help + + while getopts "dDhLUzk" opt; do + case $opt in + (d) + del=1 + ;; + + (D) + del=2 + ;; + + (h) + help=1 + ;; + + (L) + list=1 + ;; + + ([Uzk]) + autoopts+=(-$opt) + ;; + + (*) + return 1 + ;; + esac + done + shift $(( OPTIND - 1 )) + + if (( list )); then + zstyle -L "zle-(${1:-${(@j:|:)hooktypes}})" widgets + return $? + elif (( help || $# != 2 || ${hooktypes[(I)${1#zle-}]} == 0 )); then + print -u$(( 2 - help )) $usage + return $(( 1 - help )) + fi + + local -aU extant_hooks + local hook="zle-${1#zle-}" + local fn="$2" + + if (( del )); then + # delete, if hook is set + if zstyle -g extant_hooks "$hook" widgets; then + if (( del == 2 )); then + set -A extant_hooks ${extant_hooks:#(<->:|)${~fn}} + else + set -A extant_hooks ${extant_hooks:#(<->:|)$fn} + fi + # unset if no remaining entries + if (( ${#extant_hooks} )); then + zstyle "$hook" widgets "${extant_hooks[@]}" + else + zstyle -d "$hook" widgets + fi + fi + else + zstyle -g extant_hooks "$hook" widgets + extant_hooks+=("$fn") + zstyle -- "$hook" widgets "${extant_hooks[@]}" + if [[ -z "${widgets[$fn]}" ]]; then + autoload "${autoopts[@]}" -- "$fn" + zle -N "$fn" + fi + if [[ -z "${widgets[$hook]}" ]]; then + zle -N "$hook" + fi + fi +} + +# Handle zsh autoloading conventions +if [[ "$zsh_eval_context" = *loadautofunc && ! -o kshautoload ]]; then + add-zle-hook-widget "$@" +fi |