summary refs log tree commit diff
path: root/Functions/Zle/add-zle-hook-widget
blob: eeb0191f01da48c952cc506ab9a5a31c52e5cce7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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