# 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. # Othewise the widget is assigned an index that appends it to the array. # # 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. # # The -L option lists the hooks and their associated widgets. emulate -L zsh # This is probably more safeguarding than necessary zmodload -e zsh/zle || return 1 { zmodload zsh/parameter && zmodload zsh/zleparameter } || { print -u2 "Need parameter modules for zle hooks" return 1 } # Setup - create the base functions for hook widgets that call the others local -a hooktypes=( zle-isearch-exit zle-isearch-update zle-line-pre-redraw zle-line-init zle-line-finish zle-history-line-set zle-keymap-select ) # Stash in zstyle to make it global zstyle zle-hook types ${hooktypes#zle-} for hook in $hooktypes do function azhw:$hook { local -a hook_widgets local hook # Values of these styles look like number:name # and we run them in number order zstyle -a $WIDGET widgets hook_widgets for hook in "${(@)${(@on)hook_widgets[@]}#<->:}"; do zle "$hook" -Nw "$@" || return done return 0 } # Check for an existing widget, add it as the first hook if [[ ${widgets[$hook]} = user:* ]]; then zle -A "$hook" "${widgets[$hook]}" zstyle -- "$hook" widgets 0:"${widgets[$hook]}" zle -N "$hook" azhw:"$hook" fi 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 )) 1=${1#zle-} # Strip prefix not stored in zle-hook types style if (( list )); then zstyle -L "zle-(${1:-${(@j:|:)hooktypes[@]}})" widgets return $? elif (( help || $# != 2 || ${hooktypes[(I)$1]} == 0 )); then print -u$(( 2 - help )) $usage return $(( 1 - help )) fi local -aU extant_hooks local hook="zle-$1" 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 integer i=${#options[ksharrays]}-2 zstyle -g extant_hooks "$hook" widgets if [[ "$fn" != <->:* ]]; then if [[ -z ${(M)extant_hooks[@]:#(<->:|)$fn} ]]; then # no index and not already hooked # assign largest existing index plus 10 i=${${(On@)${(@M)extant_hooks[@]#<->:}%:}[i]}+10 else return 0 fi else i=${${(M)fn#<->:}%:} fn=${fn#<->:} fi extant_hooks+=("${i}:${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" azhw:"$hook" fi fi } # Handle zsh autoloading conventions if [[ "$zsh_eval_context" = *loadautofunc && ! -o kshautoload ]]; then add-zle-hook-widget "$@" fi