@@ -21,8 +21,8 @@ pub struct Taskwarrior {
21
21
update_interval : Duration ,
22
22
warning_threshold : u32 ,
23
23
critical_threshold : u32 ,
24
- filter_tags : Vec < String > ,
25
- block_mode : TaskwarriorBlockMode ,
24
+ filters : Vec < Filter > ,
25
+ filter_index : usize ,
26
26
format : FormatTemplate ,
27
27
format_singular : FormatTemplate ,
28
28
format_everything_done : FormatTemplate ,
@@ -34,6 +34,29 @@ pub struct Taskwarrior {
34
34
tx_update_request : Sender < Task > ,
35
35
}
36
36
37
+ #[ derive( Deserialize , Debug , Default , Clone ) ]
38
+ #[ serde( deny_unknown_fields) ]
39
+ pub struct Filter {
40
+ pub name : String ,
41
+ pub filter : String ,
42
+ }
43
+
44
+ impl Filter {
45
+ pub fn new ( name : String , filter : String ) -> Self {
46
+ Filter { name, filter }
47
+ }
48
+
49
+ pub fn legacy ( name : String , tags : & [ String ] ) -> Self {
50
+ let tags = tags
51
+ . iter ( )
52
+ . map ( |element| format ! ( "+{}" , element) )
53
+ . collect :: < Vec < String > > ( )
54
+ . join ( " " ) ;
55
+ let filter = format ! ( "-COMPLETED -DELETED {}" , tags) ;
56
+ Self :: new ( name, filter)
57
+ }
58
+ }
59
+
37
60
#[ derive( Deserialize , Debug , Default , Clone ) ]
38
61
#[ serde( deny_unknown_fields) ]
39
62
pub struct TaskwarriorConfig {
@@ -53,32 +76,31 @@ pub struct TaskwarriorConfig {
53
76
pub critical_threshold : u32 ,
54
77
55
78
/// A list of tags a task has to have before it's used for counting pending tasks
79
+ /// (DEPRECATED) use filters instead
56
80
#[ serde( default = "TaskwarriorConfig::default_filter_tags" ) ]
57
81
pub filter_tags : Vec < String > ,
58
82
83
+ /// A list of named filter criteria which must be fulfilled to be counted towards
84
+ /// the total, when that filter is active.
85
+ #[ serde( default = "TaskwarriorConfig::default_filters" ) ]
86
+ pub filters : Vec < Filter > ,
87
+
59
88
/// Format override
60
89
#[ serde( default = "TaskwarriorConfig::default_format" ) ]
61
90
pub format : String ,
62
91
63
- /// Format override if exactly one task is pending
92
+ /// Format override if the count is one
64
93
#[ serde( default = "TaskwarriorConfig::default_format" ) ]
65
94
pub format_singular : String ,
66
95
67
- /// Format override if all tasks are completed
96
+ /// Format override if the count is zero
68
97
#[ serde( default = "TaskwarriorConfig::default_format" ) ]
69
98
pub format_everything_done : String ,
70
99
71
100
#[ serde( default = "TaskwarriorConfig::default_color_overrides" ) ]
72
101
pub color_overrides : Option < BTreeMap < String , String > > ,
73
102
}
74
103
75
- enum TaskwarriorBlockMode {
76
- // Show only the tasks which are filtered by the set tags and which are not completed.
77
- OnlyFilteredPendingTasks ,
78
- // Show all pending tasks and ignore the filtering tags.
79
- AllPendingTasks ,
80
- }
81
-
82
104
impl TaskwarriorConfig {
83
105
fn default_interval ( ) -> Duration {
84
106
Duration :: from_secs ( 600 )
@@ -96,6 +118,13 @@ impl TaskwarriorConfig {
96
118
vec ! [ ]
97
119
}
98
120
121
+ fn default_filters ( ) -> Vec < Filter > {
122
+ vec ! [ Filter :: new(
123
+ "pending" . to_string( ) ,
124
+ "-COMPLETED -DELETED" . to_string( ) ,
125
+ ) ]
126
+ }
127
+
99
128
fn default_format ( ) -> String {
100
129
"{count}" . to_owned ( )
101
130
}
@@ -117,15 +146,22 @@ impl ConfigBlock for Taskwarrior {
117
146
let output = ButtonWidget :: new ( config. clone ( ) , & id)
118
147
. with_icon ( "tasks" )
119
148
. with_text ( "-" ) ;
149
+ // If the deprecated `filter_tags` option has been set,
150
+ // convert it to the new `filter` format.
151
+ let filters = if block_config. filter_tags . len ( ) > 0 {
152
+ vec ! [
153
+ Filter :: legacy( "filtered" . to_string( ) , & block_config. filter_tags) ,
154
+ Filter :: legacy( "all" . to_string( ) , & vec![ ] ) ,
155
+ ]
156
+ } else {
157
+ block_config. filters
158
+ } ;
120
159
121
160
Ok ( Taskwarrior {
122
161
id : pseudo_uuid ( ) ,
123
162
update_interval : block_config. interval ,
124
163
warning_threshold : block_config. warning_threshold ,
125
164
critical_threshold : block_config. critical_threshold ,
126
- filter_tags : block_config. filter_tags ,
127
- block_mode : TaskwarriorBlockMode :: OnlyFilteredPendingTasks ,
128
- output,
129
165
format : FormatTemplate :: from_string ( & block_config. format ) . block_error (
130
166
"taskwarrior" ,
131
167
"Invalid format specified for taskwarrior::format" ,
@@ -143,7 +179,10 @@ impl ConfigBlock for Taskwarrior {
143
179
"Invalid format specified for taskwarrior::format_everything_done" ,
144
180
) ?,
145
181
tx_update_request,
182
+ filter_index : 0 ,
146
183
config,
184
+ filters,
185
+ output,
147
186
} )
148
187
}
149
188
}
@@ -164,33 +203,20 @@ fn has_taskwarrior() -> Result<bool> {
164
203
!= "" )
165
204
}
166
205
167
- fn tags_to_filter ( tags : & [ String ] ) -> String {
168
- tags. iter ( )
169
- . map ( |element| format ! ( "+{}" , element) )
170
- . collect :: < Vec < String > > ( )
171
- . join ( " " )
172
- }
173
-
174
- fn get_number_of_pending_tasks ( tags : & [ String ] ) -> Result < u32 > {
206
+ fn get_number_of_tasks ( filter : & str ) -> Result < u32 > {
175
207
String :: from_utf8 (
176
208
Command :: new ( "sh" )
177
- . args ( & [
178
- "-c" ,
179
- & format ! (
180
- "task rc.gc=off -COMPLETED -DELETED {} count" ,
181
- tags_to_filter( tags)
182
- ) ,
183
- ] )
209
+ . args ( & [ "-c" , & format ! ( "task rc.gc=off {} count" , filter) ] )
184
210
. output ( )
185
211
. block_error (
186
212
"taskwarrior" ,
187
- "failed to run taskwarrior for getting the number of pending tasks" ,
213
+ "failed to run taskwarrior for getting the number of tasks" ,
188
214
) ?
189
215
. stdout ,
190
216
)
191
217
. block_error (
192
218
"taskwarrior" ,
193
- "failed to get the number of pending tasks from taskwarrior" ,
219
+ "failed to get the number of tasks from taskwarrior" ,
194
220
) ?
195
221
. trim ( )
196
222
. parse :: < u32 > ( )
@@ -202,20 +228,23 @@ impl Block for Taskwarrior {
202
228
if !has_taskwarrior ( ) ? {
203
229
self . output . set_text ( "?" )
204
230
} else {
205
- let filter_tags = match self . block_mode {
206
- TaskwarriorBlockMode :: OnlyFilteredPendingTasks => self . filter_tags . clone ( ) ,
207
- TaskwarriorBlockMode :: AllPendingTasks => vec ! [ ] ,
208
- } ;
209
- let number_of_pending_tasks = get_number_of_pending_tasks ( & filter_tags) ?;
210
- let values = map ! ( "{count}" => number_of_pending_tasks) ;
211
- self . output . set_text ( match number_of_pending_tasks {
231
+ let filter = self . filters . get ( self . filter_index ) . block_error (
232
+ "taskwarrior" ,
233
+ & format ! ( "Filter at index {} does not exist" , self . filter_index) ,
234
+ ) ?;
235
+ let number_of_tasks = get_number_of_tasks ( & filter. filter ) ?;
236
+ let values = map ! (
237
+ "{count}" => number_of_tasks. to_string( ) ,
238
+ "{filter_name}" => filter. name. clone( )
239
+ ) ;
240
+ self . output . set_text ( match number_of_tasks {
212
241
0 => self . format_everything_done . render_static_str ( & values) ?,
213
242
1 => self . format_singular . render_static_str ( & values) ?,
214
243
_ => self . format . render_static_str ( & values) ?,
215
244
} ) ;
216
- if number_of_pending_tasks >= self . critical_threshold {
245
+ if number_of_tasks >= self . critical_threshold {
217
246
self . output . set_state ( State :: Critical ) ;
218
- } else if number_of_pending_tasks >= self . warning_threshold {
247
+ } else if number_of_tasks >= self . warning_threshold {
219
248
self . output . set_state ( State :: Warning ) ;
220
249
} else {
221
250
self . output . set_state ( State :: Idle ) ;
@@ -237,14 +266,8 @@ impl Block for Taskwarrior {
237
266
self . update ( ) ?;
238
267
}
239
268
MouseButton :: Right => {
240
- match self . block_mode {
241
- TaskwarriorBlockMode :: OnlyFilteredPendingTasks => {
242
- self . block_mode = TaskwarriorBlockMode :: AllPendingTasks
243
- }
244
- TaskwarriorBlockMode :: AllPendingTasks => {
245
- self . block_mode = TaskwarriorBlockMode :: OnlyFilteredPendingTasks
246
- }
247
- }
269
+ // Increment the filter_index, rotating at the end
270
+ self . filter_index = ( self . filter_index + 1 ) % self . filters . len ( ) ;
248
271
self . update ( ) ?;
249
272
}
250
273
_ => { }
0 commit comments