-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathj.py
executable file
·182 lines (161 loc) · 5.58 KB
/
j.py
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
#!/usr/bin/env python
'''
maintains a jump-list of the directories you actually use
INSTALL:
* put something like this in your .bashrc:
export JPY=/path/to/j.py # tells j.sh where the python script is
. /path/to/j.sh # provides the j() function
* make sure j.py is executable
* cd around for a while to build up the db
* PROFIT!!
USE:
* j foo # goes to most frecent dir matching foo
* j foo bar # goes to most frecent dir matching foo and bar
* j -t rank # goes to highest ranked dir matching foo
* j -l foo # list all dirs matching foo
'''
import os, sys, time
class J(object):
def __init__(self, datafile):
''' datafile format: path|rank|atime '''
self.datafile = datafile
self.common = None
self.args = []
self.m = []
self.ordered = { 'rank' : self.rank,
'recent' : self.recent,
'frecent': self.frecent }
# get list
try:
with open(self.datafile, 'r') as f:
self.d = [l.strip().split('|') for l in f.readlines()]
self.d = [d for d in self.d if os.path.exists(d[0])]
except:
self.d = []
# rewrite to disk
with open(self.datafile, 'w') as f:
f.write('\n'.join(['|'.join(d) for d in self.d]))
f.write('\n')
def pretty(self, order):
''' return a listing by order '''
if order not in self.ordered:
return ''
r = ['by %s' % order]
r.extend(['%-15s %s' % i for i in self.ordered[order]()])
return '\n'.join(r)
def go(self, order):
''' go by order '''
if order == 'common':
return self.common
if self.m and order in self.ordered:
return self.ordered[order]()[-1][1]
def rank(self):
''' time spent/aging, taken care of in .sh '''
r = ([(i[0], i[2]) for i in self.m])
return sorted(r)
def recent(self):
''' by recently accessed '''
r = ([(i[1], i[2]) for i in self.m])
return sorted(r, reverse=True)
def frecent(self):
''' rank weighted by recently accessed '''
r = []
for i in self.m:
if i[1] <= 3600:
r.append((i[0]*4, i[2]))
elif i[1] <= 86400:
r.append((i[0]*2, i[2]))
elif i[1] <= 604800:
r.append((i[0]/2, i[2]))
else:
r.append((i[0]/4, i[2]))
return sorted(r)
def matches(self, args, nocase=False):
'''
set self.m to a list of possibly case sensitive path matches
m format: (rank, atime, path)
'''
def common(r, l, nocase):
'''
return prefix if there's a common prefix to all matches,
the prefix is in the list,
and all the args match in it
'''
pref = os.path.commonprefix([i[2] for i in r])
if not pref or pref == '/':
return None
r = [i for i in r if i[2] == pref]
if not r:
return None
if nocase:
pref = pref.lower()
for i in l:
if i not in pref:
return None
return r[0][2]
def cmpare(str, l, nocase):
''' every item in list l must match in string str '''
match = True
if nocase:
str = str.lower()
for i in l:
if i not in str:
match = False
return match
self.args, self.m = args, []
if nocase:
args = [i.lower() for i in args]
for d in self.d:
if not cmpare(d[0], args, nocase):
continue
self.m.append((float(d[1]),
int(time.time())-int(d[2]),
d[0]))
self.common = common(self.m, args, nocase)
return self.m
def main(file, list, type, args):
''' make sure the only thing that gets to stdout is a place to cd '''
if not file:
return
# if we hit enter on a completion, go there
if args and os.path.isdir(args[-1]):
sys.stdout.write(os.path.realpath(args[-1]))
return
j = J(file)
# prefer case sensitive
if not j.matches(args):
j.matches(args, True)
if list or not args:
sys.stderr.write(j.pretty(type) + '\n')
if j.common:
sys.stderr.write('common: %s\n' % j.common)
# if all our args match a common prefix, let's go there
elif j.common:
sys.stdout.write(j.common)
else:
go = j.go(type)
if not go:
return
sys.stdout.write(go)
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser(usage='%prog -f datafile [options] args')
parser.add_option('-f', '--file', help='data file')
parser.add_option('-l', action='store_true', default=False,
help='list matches')
parser.add_option('-t', default='frecent',
help='match type [frecent (default), rank, recent]')
parser.add_option('-V', action='store_true', default=False,
help='documentation')
saveout = sys.stdout
sys.stdout = sys.stderr
opts, args = parser.parse_args()
if opts.V:
sys.stdout.write(__doc__)
elif not opts.file:
parser.error('data file required (-f file)')
elif opts.t not in ['frecent', 'rank', 'recent']:
parser.print_help()
else:
sys.stdout = saveout
main(opts.file, opts.l, opts.t, args)