13
13
# set $_Z_NO_RESOLVE_SYMLINKS to prevent symlink resolution.
14
14
# set $_Z_NO_PROMPT_COMMAND if you're handling PROMPT_COMMAND yourself.
15
15
# set $_Z_EXCLUDE_DIRS to an array of directories to exclude.
16
+ # set $_Z_OWNER to your username if you want use z while sudo with $HOME kept
16
17
#
17
18
# USE:
18
19
# * z foo # cd to most frecent dir matching foo
30
31
31
32
local datafile=" ${_Z_DATA:- $HOME / .z} "
32
33
33
- # bail if we don't own ~/.z (we're another user but our ENV is still set)
34
- [ -f " $datafile " -a ! -O " $datafile " ] && return
34
+ # bail if we don't own ~/.z and $_Z_OWNER not set
35
+ [ -z " $_Z_OWNER " -a - f " $datafile " -a ! -O " $datafile " ] && return
35
36
36
37
# add entries
37
38
if [ " $1 " = " --add" ]; then
@@ -40,10 +41,10 @@ _z() {
40
41
# $HOME isn't worth matching
41
42
[ " $* " = " $HOME " ] && return
42
43
43
- # don't track excluded dirs
44
+ # don't track excluded directory trees
44
45
local exclude
45
46
for exclude in " ${_Z_EXCLUDE_DIRS[@]} " ; do
46
- [ " $* " = " $exclude " ] && return
47
+ case " $* " in " $exclude * " ) return ;; esac
47
48
done
48
49
49
50
# maintain the data file
68
69
count += $2
69
70
}
70
71
END {
71
- if( count > 6000 ) {
72
+ if( count > 9000 ) {
72
73
# aging
73
74
for( x in rank ) print x "|" 0.99*rank[x] "|" time[x]
74
75
} else for( x in rank ) print x "|" rank[x] "|" time[x]
@@ -78,42 +79,41 @@ _z() {
78
79
if [ $? -ne 0 -a -f " $datafile " ]; then
79
80
env rm -f " $tempfile "
80
81
else
81
- env mv -f " $tempfile " " $datafile " || env rm -f " $tmpfile "
82
+ [ " $_Z_OWNER " ] && chown $_Z_OWNER :$( id -ng $_Z_OWNER ) " $tempfile "
83
+ env mv -f " $tempfile " " $datafile " || env rm -f " $tempfile "
82
84
fi
83
85
84
86
# tab completion
85
- elif [ " $1 " = " --complete" ]; then
87
+ elif [ " $1 " = " --complete" -a -s " $datafile " ]; then
86
88
while read line; do
87
89
[ -d " ${line%% \| * } " ] && echo $line
88
90
done < " $datafile " | awk -v q=" $2 " -F" |" '
89
91
BEGIN {
90
92
if( q == tolower(q) ) imatch = 1
91
- split(substr(q, 3), fnd, " ")
93
+ q = substr(q, 3)
94
+ gsub(" ", ".*", q)
92
95
}
93
96
{
94
97
if( imatch ) {
95
- for( x in fnd ) tolower($1) !~ tolower(fnd[x]) && $1 = ""
96
- } else {
97
- for( x in fnd ) $1 !~ fnd[x] && $1 = ""
98
- }
99
- if( $1 ) print $1
98
+ if( tolower($1) ~ tolower(q) ) print $1
99
+ } else if( $1 ~ q ) print $1
100
100
}
101
101
' 2> /dev/null
102
102
103
103
else
104
104
# list/go
105
105
while [ " $1 " ]; do case " $1 " in
106
- --) while [ " $1 " ]; do shift ; local fnd=" $fnd $1 " ; done ;;
106
+ --) while [ " $1 " ]; do shift ; local fnd=" $fnd ${fnd : + } $1 " ; done ;;
107
107
-* ) local opt=${1: 1} ; while [ " $opt " ]; do case ${opt: 0: 1} in
108
108
c) local fnd=" ^$PWD $fnd " ;;
109
109
h) echo " ${_Z_CMD:- z} [-chlrtx] args" >&2 ; return ;;
110
- x) sed -i " \:^${PWD} |.*:d" " $datafile " ;;
110
+ x) sed -i -e " \:^${PWD} |.*:d" " $datafile " ;;
111
111
l) local list=1;;
112
112
r) local typ=" rank" ;;
113
113
t) local typ=" recent" ;;
114
114
esac ; opt=${opt: 1} ; done ;;
115
- * ) local fnd=" $fnd $1 " ;;
116
- esac ; local last=$1 ; shift ; done
115
+ * ) local fnd=" $fnd ${fnd : + } $1 " ;;
116
+ esac ; local last=$1 ; [ " $# " -gt 0 ] && shift ; done
117
117
[ " $fnd " -a " $fnd " != " ^$PWD " ] || local list=1
118
118
119
119
# if we hit enter on a completion just go there
@@ -163,22 +163,23 @@ _z() {
163
163
# use a copy to escape special characters, as we want to return
164
164
# the original. yeah, this escaping is awful.
165
165
clean_short = short
166
- gsub(/[\(\)\[\]\|]/, "\\\\&", clean_short)
166
+ gsub(/\ [\(\)\[\]\|\ ]/, "\\\\&", clean_short)
167
167
for( x in matches ) if( matches[x] && x !~ clean_short ) return
168
168
return short
169
169
}
170
- BEGIN { split(q, words, " "); hi_rank = ihi_rank = -9999999999 }
170
+ BEGIN {
171
+ gsub(" ", ".*", q)
172
+ hi_rank = ihi_rank = -9999999999
173
+ }
171
174
{
172
175
if( typ == "rank" ) {
173
176
rank = $2
174
177
} else if( typ == "recent" ) {
175
178
rank = $3 - t
176
179
} else rank = frecent($2, $3)
177
- matches[$1] = imatches[$1] = rank
178
- for( x in words ) {
179
- if( $1 !~ words[x] ) delete matches[$1]
180
- if( tolower($1) !~ tolower(words[x]) ) delete imatches[$1]
181
- }
180
+ if( $1 ~ q ) {
181
+ matches[$1] = rank
182
+ } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank
182
183
if( matches[$1] && matches[$1] > hi_rank ) {
183
184
best_match = $1
184
185
hi_rank = matches[$1]
@@ -219,7 +220,7 @@ if compctl >/dev/null 2>&1; then
219
220
}
220
221
fi
221
222
[[ -n " ${precmd_functions[(r)_z_precmd]} " ]] || {
222
- precmd_functions+=( _z_precmd)
223
+ precmd_functions[ $(( $# precmd_functions + 1 )) ]= _z_precmd
223
224
}
224
225
}
225
226
_z_zsh_tab_completion () {
@@ -236,7 +237,7 @@ elif complete >/dev/null 2>&1; then
236
237
[ " $_Z_NO_PROMPT_COMMAND " ] || {
237
238
# populate directory list. avoid clobbering other PROMPT_COMMANDs.
238
239
grep " _z --add" <<< " $PROMPT_COMMAND" > /dev/null || {
239
- PROMPT_COMMAND=" $PROMPT_COMMAND " $' \n ' ' _z --add "$(pwd ' $_Z_RESOLVE_SYMLINKS ' 2>/dev/null)" 2>/dev/null;'
240
+ PROMPT_COMMAND=" $PROMPT_COMMAND " $' \n ' ' _z --add "$(command pwd ' $_Z_RESOLVE_SYMLINKS ' 2>/dev/null)" 2>/dev/null;'
240
241
}
241
242
}
242
- fi
243
+ fi
0 commit comments