blob: aa4bf9b84c6deaef9b414cef9a51c988b8fe0cfb (
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
|
## zsh_directory_name_generic
#
# This function is useful as a hook function for the zsh_directory_name
# facility.
#
# See the zsh-contrib manual page for more.
emulate -L zsh
setopt extendedglob
local -a match mbegin mend
# The variable containing the top level mapping.
local _zdn_topvar
zmodload -i zsh/parameter
zstyle -s ":zdn:${funcstack[2]}:" mapping _zdn_topvar || _zdn_topvar=zdn_top
if (( ! ${(P)#_zdn_topvar} )); then
print -r -- "$0: $_zdn_topvar is not set" >&2
return 1
fi
local _zdn_var=$_zdn_topvar
local -A _zdn_assoc
if [[ $1 = n ]]; then
# Turning a name into a directory.
local _zdn_name=$2
local -a _zdn_words
local _zdn_dir _zdn_cpt
_zdn_words=(${(s.:.)_zdn_name})
while (( ${#_zdn_words} )); do
if [[ -z ${_zdn_var} ]]; then
print -r -- "$0: too many components in directory name \`$_zdn_name'" >&2
return 1
fi
# Subscripting (P)_zdn_var directly seems not to work.
_zdn_assoc=(${(Pkv)_zdn_var})
_zdn_cpt=${_zdn_assoc[${_zdn_words[1]}]}
shift _zdn_words
if [[ -z $_zdn_cpt ]]; then
# If top level component, just try another expansion
if [[ $_zdn_var != $_zdn_topvar ]]; then
# Committed to this expansion, so report failure.
print -r -- "$0: no expansion for directory name \`$_zdn_name'" >&2
fi
return 1
fi
if [[ $_zdn_cpt = (#b)(*)/:([[:IDENT:]]##) ]]; then
_zdn_cpt=$match[1]
_zdn_var=$match[2]
else
# may be empty
_zdn_var=${${_zdn_assoc[:default:]}##*/:}
fi
_zdn_dir=${_zdn_dir:+$_zdn_dir/}$_zdn_cpt
done
if (( ${#_zdn_dir} )); then
typeset -ag reply
reply=($_zdn_dir)
return 0
fi
elif [[ $1 = d ]]; then
# Turning a directory into a name.
local _zdn_dir=$2
local _zdn_rest=$_zdn_dir
local -a _zdn_cpts
local _zdn_pref _zdn_pref_raw _zdn_matched _zdn_cpt _zdn_name
while [[ -n $_zdn_var && -n $_zdn_rest ]]; do
_zdn_assoc=(${(Pkv)_zdn_var})
# Sorting in descending order will ensure prefixes
# come after longer strings with that perfix, so
# we match more specific directory names preferentially.
_zdn_cpts=(${(Ov)_zdn_assoc})
_zdn_cpt=''
for _zdn_pref_raw in $_zdn_cpts; do
_zdn_pref=${_zdn_pref_raw%/:*}
[[ -z $_zdn_pref ]] && continue
if [[ $_zdn_rest = $_zdn_pref(#b)(/|)(*) ]]; then
_zdn_cpt=${(k)_zdn_assoc[(r)$_zdn_pref_raw]}
# if we matched a /, too, add it...
_zdn_matched+=$_zdn_pref$match[1]
_zdn_rest=$match[2]
break
fi
done
if [[ -n $_zdn_cpt ]]; then
_zdn_name+=${_zdn_name:+${_zdh_name}:}$_zdn_cpt
if [[ ${_zdn_assoc[$_zdn_cpt]} = (#b)*/:([[:IDENT:]]##) ]]; then
_zdn_var=$match[1]
else
_zdn_var=${${_zdn_assoc[:default:]}##*/:}
fi
else
break
fi
done
if [[ -n $_zdn_name ]]; then
# matched something, so report that.
integer _zdn_len=${#_zdn_matched}
[[ $_zdn_matched[-1] = / ]] && (( _zdn_len-- ))
typeset -ag reply
reply=($_zdn_name $_zdn_len)
return 0
fi
# else let someone else have a go.
elif [[ $1 = c ]]; then
# Completion
if [[ -n $SUFFIX ]]; then
_message "Can't complete in the middle of a dynamic directory name"
else
local -a _zdn_cpts
local _zdn_word _zdn_cpt _zdn_desc _zdn_sofar expl
while [[ -n ${_zdn_var} && ${PREFIX} = (#b)([^:]##):* ]]; do
_zdn_word=$match[1]
compset -P '[^:]##:'
_zdn_assoc=(${(Pkv)_zdn_var})
_zdn_cpt=${_zdn_assoc[$_zdn_word]}
# We only complete at the end so must match here
[[ -z $_zdn_cpt ]] && return 1
if [[ $_zdn_cpt = (#b)(*)/:([[:IDENT:]]##) ]]; then
_zdn_cpt=$match[1]
_zdn_var=$match[2]
else
_zdn_var=${${_zdn_assoc[:default:]}##*/:}
fi
_zdn_sofar+=${_zdn_sofar:+${_zdn_sofar}/}$_zdn_cpt
done
if [[ -n $_zdn_var ]]; then
_zdn_assoc=(${(Pkv)_zdn_var})
local -a _zdn_cpts
for _zdn_cpt _zdn_desc in ${(kv)_zdn_assoc}; do
[[ $_zdn_cpt = :* ]] && continue
_zdn_cpts+=(${_zdn_cpt}:${_zdn_desc%/:[[:IDENT:]]##})
done
_describe -t dirnames "directory name under ${_zdn_sofar%%/}" \
_zdn_cpts -S: -r ':]'
return
fi
fi
fi
# Failed
return 1
## end
|