about summary refs log tree commit diff
path: root/Functions/Completion/init
blob: 35e7f6a3c76d18b6f34e0547a0fb4edc0b91b1af (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# 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 a underscores (like `_setopt).
# The first line of these files will be read and has to say what should be
# done with its contents:
#
#   `#defcomp <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
#
#   `#defpatcomp <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
#
#   `#defkeycomp <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.
#
#   `#autoload'
#     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.
#
# See the file `dump' for how to speed up initialiation.

# If we got the `-d'-flag, we will automatically dump the new state (at
# the end).

if [[ "$1" = -d ]]; then
  _i_autodump=1
else
  _i_autodump=0
fi

# The associative array containing the definitions for the commands.
# Definitions for patterns will be stored in the normal array `patcomps'.

typeset -A comps


# This may be used to define completion handlers. The first argument is the
# name of the function 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

  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
# 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"
  fi
  name="$1"
  shift
  zle -C "$name" "$1" "$name"
  shift
  while (( $# )); do
    bindkey "$1" "$name"
    shift
  done
}

# This searches $1 in the array for normal completions and calls the result.

_compalso() {
  local tmp

  tmp="$comps[$1]"
  [[ -z "$tmp" ]] || "$tmp" "$@"
}

# These can be used to easily save and restore the state of the special
# variables used by the completion code.

alias _compsave='local _oprefix$_level _oiprefix$_level _oargv$_level _ocurrent$_level _ocommand$_level _ocontext$_level; \
                eval "_oprefix${_level}=\"\$PREFIX\"; \
                      _oiprefix${_level}=\"\$IPREFIX\"; \
                      _oargv${_level}=( \"\$@\" ); \
                      _ocurrent${_level}=\"\$CURRENT\"; \
		      _ocommand${_level}=\"\$COMMAND\"; \
		      _ocontext${_level}=\"\$CONTEXT\""'
alias _compreset='eval "PREFIX=\"\$_oprefix${_level}\"; \
                        IPREFIX=\"\$_oiprefix${_level}\"; \
                        argv=( \"\$_oargv${_level}[@]\" ); \
	  	        CURRENT=\"\$_ocur${_level}\"; \
                        COMMAND=\"\$_ocommand${_level}\"; \
                        CONTEXT=\"\$_ocontext${_level}\""'

# These can be used to build tests that modify the special parameters
# without having to reset them by hand.

alias _if='(( $+_level )) || local _level=0; (( _level++ )); _compsave; if'
alias _elif='_compreset; elif'
alias _else='_compreset; else'
alias _fi='_compreset; fi; unset _oprefix$_level _oiprefix$_level _oargv$_level _ocurrent$_level _ocommand$_level _ocontext$_level; (( _level-- ))'


# Now we automatically make the definition files autoloaded.

# First we get the name of a dump file if this will be used.

: ${COMPDUMP:=$0.dump}

_i_files=( ${^~fpath}/_*~*~ )
_i_initname=$0
_i_done=''

# If we have a dump file, load it.

if [[ -f "$COMPDUMP" ]]; then
  read -rA _i_line < "$COMPDUMP"
  if [[ _i_autodump -eq 1 || $_i_line[2] -eq $#_i_files ]]; then
    builtin . "$COMPDUMP"
    _i_done=yes
  fi
  unset _i_line
fi
if [[ -z "$_i_done" ]]; then

  for _i_dir in $fpath; do
    [[ $_i_dir = . ]] && continue
    for _i_file in $_i_dir/_*~*~(N); do
      read -rA _i_line < $_i_file
      _i_tag=$_i_line[1]
      shift _i_line
      if [[ $_i_tag = '#defcomp' ]]; then
	defcomp -a ${_i_file:t} "${_i_line[@]}"
      elif [[ $_i_tag = '#defpatcomp' ]]; then
	defpatcomp -a "${_i_file:t}" "${_i_line[@]}"
      elif [[ $_i_tag = '#defkeycomp' ]]; then
	defkeycomp -a "${_i_file:t}" "${_i_line[@]}"
      elif [[ $_i_tag = '#autoload' ]]; then
	autoload ${_i_file:t}
      fi
    done
  done

  bindkey |
    while read -rA _i_line; do
      if [[ "$_i_line[2]" = complete-word ||
	"$_i_line[2]" = delete-char-or-list ||
	"$_i_line[2]" = expand-or-complete ||
	"$_i_line[2]" = expand-or-complete-prefix ||
	"$_i_line[2]" = list-choices ||
	"$_i_line[2]" = menu-complete ||
	"$_i_line[2]" = menu-expand-or-complete ||
	"$_i_line[2]" = reverse-menu-complete ]]; then
	zle -C _complete_$_i_line[2] $_i_line[2] _main_complete
	bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2]
      fi
    done

  unset _i_dir _i_line _i_file _i_tag

  # if autodumping was requested, do it now.

  (( _i_autodump )) && builtin . ${_i_initname:h}/dump
fi

unset _i_files _i_initname _i_done _i_autodump