-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfgrun
executable file
·66 lines (59 loc) · 2.33 KB
/
fgrun
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
#!/usr/bin/env python
import os, sys, pathlib as pl, subprocess as sp
def main(args=None):
dmenu_history_hwm = 10 * 2**10
dmenu_history = pl.Path('~/.fgrun.history').expanduser()
dmenu_cache = pl.Path('~/.fgrun.cache').expanduser()
dmenu_cache_end = '-=puǝ=-'
dmenu_args = ['-p', 'Run:', '-i', '-m', '2', '-fn', 'Luxi Sans-8:normal']
# Read caches
try:
dmenu_cache_ts = dmenu_cache.stat().st_mtime
dcache = dmenu_cache.read_text().split('\0')
if dcache[-1] != dmenu_cache_end: raise OSError
dcache = dict((s[0], s[1:]) for s in (s.split(' ') for s in dcache[:-1]))
except OSError: dcache, dmenu_cache_ts = dict(), 0
try: history = list(s for s in dmenu_history.read_text().splitlines() if s)
except OSError: history = list()
if os.environ.get('FGRUN_RECACHE'): dmenu_cache_ts = 0
# Update caches
dcache_update, paths = False, set()
for s in os.environ.get('PATH', '').split(':'):
if not s.strip(): continue
try: p_mtime = (p := pl.Path(s).resolve(True)).stat().st_mtime
except OSError: continue
if (ps := str(p)) in paths: continue
if ps not in dcache or p_mtime > dmenu_cache_ts:
try: dcache[ps] = list(b for b in os.listdir(ps) if ' ' not in b)
except OSError: continue
dcache_update = True
paths.add(ps)
for ps in set(dcache).difference(paths):
del dcache[ps]; dcache_update = True
# Run dmenu
dmenu_list = dict.fromkeys(reversed(history))
for ext in dcache.values(): dmenu_list.update(dict.fromkeys(ext))
dmenu_list[''] = None
dmenu = sp.Popen(
['dmenu'] + dmenu_args, stdin=sp.PIPE, stdout=sp.PIPE )
dmenu.stdin.write('\n'.join(dmenu_list).encode())
dmenu.stdin.close()
run = dmenu.stdout.read().strip().decode()
if dmenu.wait() != 0: run = None
# Write caches, run app
if dcache_update:
(tmp := dmenu_cache.with_name(dmenu_cache.name + '.new')).write_text(
'\0'.join([*(' '.join([k,*v]) for k,v in dcache.items()), dmenu_cache_end]) )
tmp.rename(dmenu_cache)
if not run: return
try: hist_sz = dmenu_history.stat().st_size
except OSError: pass
history.append(run)
if hist_sz >= dmenu_history_hwm: # deduplicate
history = list(reversed(list(dict.fromkeys(reversed(history)))))
history.append('')
(tmp := dmenu_history.with_name(
dmenu_history.name + '.new' )).write_text('\n'.join(history))
tmp.rename(dmenu_history)
os.execvp(run, [run] + sys.argv[1:])
if __name__ == '__main__': sys.exit(main())