-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhitlist
More file actions
executable file
·122 lines (104 loc) · 3.73 KB
/
hitlist
File metadata and controls
executable file
·122 lines (104 loc) · 3.73 KB
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
#!/usr/bin/python3
"""
Run a command periodically, which outputs "Things to do", one per line.
As each disappears, change its color to red (done) and add how long it took to remove.
Save the score list to a file.
"""
import argparse
import os
import re
import shlex
import subprocess
import sys
from time import time, sleep
def run_command(command):
x = subprocess.check_output(' '.join(command), shell=True).decode("utf8")
return x.split("\n")[:-1]
def p(f, s, color):
if f == sys.stdout:
cols = os.get_terminal_size().columns
s = s[:cols]
if color:
s = f"\x1B[{color}{s}\x1B[0m"
print(s, file=f)
def write_file(file, header, items, times):
p(file, header, None)
p(file, "", None)
for item in items:
t = times[item]
if t:
p(file, f"{item} [{int(t)}s]", "32;40m")
else:
p(file, item, "94;40m")
def loop(delay, command, filename):
header = ' '.join(shlex.quote(x) for x in command)
header = f"every {delay:.1f}s: {header}"
first_seen = {}
last_seen = {}
currently_visible = {}
start = time()
# Load from score file to continue
if filename is not None and os.path.exists(filename):
with open(filename, "r") as f:
for line in list(f)[2:]:
line = line.removesuffix("\n")
if m := re.fullmatch(r"(.*) \[(\d+)s\]", line):
item, s = m.group(1), int(m.group(2))
else:
item, s = line, 0
last_seen[item] = start
first_seen[item] = start-s
currently_visible[item] = False
while True:
items, now = run_command(command), time()
finished_at = {}
for k in items:
if k not in first_seen:
first_seen[k] = now
last_seen[k] = now
for k in currently_visible:
currently_visible[k] = False
finished_at[k] = last_seen[k]+delay
for k in items:
currently_visible[k] = True
finished_at[k] = None
# compute delta times
# if one task was finished 80s after start, and one 93s after the start,
# the second task "took" 13s
time_taken = {}
delta_time = {}
unique_times = sorted(set(finished_at.values())-{None})
for a,b in zip([start]+unique_times[:-1], unique_times):
delta_time[b]=b-a
for k in finished_at:
time_taken[k] = delta_time.get(finished_at[k])
ever_seen = sorted(
currently_visible.keys(),
key=lambda k: (not currently_visible[k], last_seen[k], first_seen[k]),
)
# Display
sys.stdout.write("\x1B[2J\x1B[H") # Clear the screen and home the cursor
height = os.get_terminal_size().lines
write_file(sys.stdout, header, ever_seen[:height-3], time_taken)
# Write to file
if filename is not None:
with open(filename, "w") as f:
write_file(f, header, ever_seen, time_taken)
sleep(delay)
if __name__ == "__main__":
delay = 1
command = "cat ~/a.txt"
filename = "home_dir.txt"
parser = argparse.ArgumentParser(
prog="hitlist",
description="Combination between 'watch' and a TODO list",
)
parser.add_argument('--score-file', action="store", default="hitlist-score.txt")
parser.add_argument('--no-score-file', action="store_const", dest="score_file")
parser.add_argument("-n", "--interval", action="store", type=int, default=1)
parser.add_argument("command", nargs="+")
args = parser.parse_args()
try:
loop(delay=args.interval, command=args.command, filename=args.score_file)
except KeyboardInterrupt:
pass