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
|
#!/bin/bash
# pure shell version of 'new j'
# has frecency, rank, and recent
# has common and case preference
# lists to stderr
# protect multiple PROMPT_COMMAND appends
j() {
local datafile=$HOME/.j
if [ "$1" = "--add" ]; then
# add
shift
# $HOME isn't worth matching
[ "$*" = "$HOME" ] && return
awk -v q="$*" -v t="$(date +%s)" -F"|" '
BEGIN { l[q] = 1; d[q] = t }
$2 >= 1 {
if( $1 == q ) {
l[$1] = $2 + 1
d[$1] = t
} else {
l[$1] = $2
d[$1] = $3
}
count += $2
}
END {
if( count > 1000 ) {
for( i in l ) print i "|" 0.9*l[i] "|" d[i] # aging
} else for( i in l ) print i "|" l[i] "|" d[i]
}
' $datafile 2>/dev/null > $datafile.tmp
mv -f $datafile.tmp $datafile
elif [ "$1" = "--complete" ]; then
# tab completion
awk -v q="$2" -F"|" '
BEGIN { split(substr(q,3),a," ") }
{
if( system("test -d \"" $1 "\"") ) next
for( i in a ) $1 !~ a[i] && $1 = ""; if( $1 ) print $1
}
' $datafile 2>/dev/null
else
# list/go
while [ "$1" ]; do case $1 in
-h) echo "j [-h][-l][-r][-t] args" >/dev/stderr; return;;
-l) local list=1;;
-r) local typ="rank";;
-t) local typ="recent";;
--) while [ "$1" ]; do shift; local q="$q $1";done;;
*) local q="$q $1";;
esac; local n=$1; shift; done
[ "$q" ] || local list=1
# if we hit enter on a completion just go there
[ -d "$n" ] && {
cd "$n"
return
}
cd="$(awk -v t="$(date +%s)" -v list="$list" -v typ="$typ" -v q="$q" -F"|" '
function frecent(rank, time) {
dx = t-time
if( dx < 3600 ) return rank*4
if( dx < 86400 ) return rank*2
if( dx < 604800 ) return rank/2
return rank/4
}
function output(r, s, c) {
if( list ) {
if( typ == "recent" ) {
cmd = "sort -nr >/dev/stderr"
} else cmd = "sort -n >/dev/stderr"
for( i in r ) if( r[i] ) printf "%-15s %s\n", r[i], i | cmd
if( c ) printf "%-15s %s\n", "common:", c > "/dev/stderr"
} else {
if( c ) s = c
print s
}
}
function common(r, a, nc) {
for( i in r ) {
if( ! r[i] ) continue
if( !shortest || length(i) < length(shortest) ) shortest = i
}
if( shortest == "/" ) return
for( i in r ) {
if( ! r[i] ) continue
if( i !~ shortest ) x = 1
}
if( x ) return
if( nc ) {
for( i in a ) if( tolower(shortest) !~ tolower(a[i]) ) x = 1
} else for( i in a ) if( shortest !~ a[i] ) x = 1
if( !x ) return shortest
}
BEGIN { split(q, a, " ") }
{
if( system("test -d \"" $1 "\"") ) next
if( typ == "rank" ) {
f = $2
} else if( typ == "recent" ) {
f = t-$3
} else f = frecent($2, $3)
case[$1] = nocase[$1] = f
for( i in a ) if( $1 !~ a[i] ) delete case[$1]
for( i in a ) if( tolower($1) !~ tolower(a[i]) ) delete nocase[$1]
if( case[$1] > oldf ) {
cx = $1
oldf = case[$1]
} else if( nocase[$1] > noldf ) {
ncx = $1
noldf = nocase[$1]
}
print $0 >> FILENAME ".tmp"
}
END {
if( cx ) {
output(case, cx, common(case, a, 0))
} else if( ncx ) {
output(nocase, ncx, common(nocase, a, 1))
}
}
' $datafile)"
mv -f $datafile.tmp $datafile
[ "$cd" ] && cd "$cd"
fi
}
# tab completion
complete -C 'j --complete "$COMP_LINE"' j
# populate directory list. avoid clobbering other PROMPT_COMMANDs.
echo $PROMPT_COMMAND | grep -q "j --add" || {
PROMPT_COMMAND='j --add "$(pwd -P)";'"$PROMPT_COMMAND"
}
|