-
Notifications
You must be signed in to change notification settings - Fork 0
/
taskw.py
executable file
·205 lines (143 loc) · 5.42 KB
/
taskw.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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/usr/bin/env python3
"""Extracts information from taskwarrior and timewarrior to display in i3block."""
# This is taskw.py v0.3.1
import subprocess
import json
import os
import re
# config options code
def _default(name, default="", arg_type=str):
"""
Set a parameter based on OS variable.
Fix the argument type and fall back on given default.
"""
val = default
if name in os.environ:
val = os.environ[name]
return arg_type(val)
def _strbool(s):
"""Return True if argument is t,T,true,TRUE etc."""
return s.lower() in ["t", "true", "1"]
# I don't know who originally wrote these functions,
# but many of the python blocklets in i3blocks-contrib use it.
# arch-update added this code on 25 March 2018 and as far as I can tell
# this was the earliest use.
maxlen = _default("TASKW_MAX_LENGTH", default=35, arg_type=int)
notask_msg = _default("TASKW_NOTASK_MSG", default="No Task", arg_type=str)
urgency_tf = _default("TASKW_SORT_URGENCY", default="f", arg_type=_strbool)
taskw_tf = _default("TASKW_TF", default="t", arg_type=_strbool)
timew_tf = _default("TIMEW_TF", default="f", arg_type=_strbool)
pending_tasks_tf = _default("TASKW_PENDING_TF", default="f", arg_type=_strbool)
timew_desc_override = _default("TIMEW_DESC_OVERRIDE", default="f", arg_type=_strbool)
main_filter = _default("TASKW_MAIN_FILTER", default="+ACTIVE", arg_type=str)
# Set timew_tf to true if the override is set.
if timew_desc_override:
timew_tf = True
##############################
# TESTING TESTING TESTING
# taskw_tf = False
# timew_tf = True
# timew_desc_override = True
# pending_tasks_tf = True
# notask_msg = "~No Task~"
##############################
# text output helper functions
def shorten(string, maxlen=maxlen):
"""Shorten a string to maxlen characters or fewer."""
if len(string) <= maxlen:
return string
else:
return string[: maxlen - 3] + "..."
# taskw functions
def get_taskw_json(filter_string):
"""Take a taskw filter and returns the json output for task export."""
return json.loads(
subprocess.check_output("task " + filter_string + " export", shell=True)
)
def sort_taskw_info(taskw_json):
"""
Return task description to display plus number of tasks.
Take json output from taskw and return the correct task description
to display and also the number of tasks matching the filter.
"""
max_urg = 0
if len(taskw_json) > 0:
if urgency_tf:
for i in range(len(taskw_json)):
if taskw_json[i]["urgency"] > taskw_json[max_urg]["urgency"]:
max_urg = i
return taskw_json[max_urg]["description"], len(taskw_json)
else:
return notask_msg, 0
def get_taskw_info(taskw_filter=main_filter):
"""Take a filter and return a task description and number of tasks."""
j = get_taskw_json(taskw_filter)
return sort_taskw_info(j)
def export_pending():
"""Return number of taskw pending tasks."""
return len(get_taskw_json("+PENDING"))
# timew functions
def get_timew_bytes(dom_string):
"""Return byte output from calling timew."""
try:
out = subprocess.check_output("timew get " + dom_string, shell=True)
except subprocess.CalledProcessError:
out = b""
return out
def decode_timew_bytes(in_bytes):
"""
Take timew byte input and return string.
This function also strips the trailing newline.
"""
to_string = in_bytes.decode("utf-8")[:-1]
return to_string
def get_timew_string(dom_string):
"""Return string decoded output from calling timew with dom_string."""
in_string = get_timew_bytes(dom_string)
return decode_timew_bytes(in_string)
def get_timew_active():
"""Return True if timew has active tracking."""
return b"1" in get_timew_bytes("dom.active")
def export_timew_description():
"""
Extract description from timew output.
Actually extracts first tag.
"""
timew_txt = get_timew_string("dom.active.tag.1")
return timew_txt if get_timew_active() else notask_msg
def pad_time(s):
"""Add '0' to number if necessary."""
return s if len(s) == 2 else "0" + s
def extract_time(delimiter, input_string):
"""Extract number of hours|minutes|seconds from timew output."""
match_list = re.findall(r"\d?\d" + delimiter, input_string)
return pad_time(match_list[0][:-1]) if len(match_list) > 0 else "00"
def translate_timew_string(timew_in_str):
"""Turn timew output time into duration in HH:MM format."""
duration_hrs = extract_time("H", timew_in_str)
duration_mins = extract_time("M", timew_in_str)
return duration_hrs + ":" + duration_mins
def main():
"""Return string to display based on params."""
task_desc = ""
task_append = ""
timew_duration = ""
pending_text = ""
if taskw_tf:
descr, task_num = get_taskw_info()
task_desc = shorten(descr)
if task_num > 1:
task_append = " + " + str(task_num - 1)
if timew_tf:
get_string = get_timew_string("dom.active.duration")
timew_duration = (
translate_timew_string(get_string) + " " if get_timew_active() else ""
)
if timew_desc_override or not taskw_tf:
task_desc = shorten(export_timew_description())
if pending_tasks_tf:
pending_text = f" [{export_pending()}]"
bar_text = timew_duration + task_desc + task_append + pending_text
return bar_text
if __name__ == "__main__":
print(main())