@@ -64,7 +64,7 @@ pub async fn run(config: Config, mut api: CommonApi) -> Result<()> {
64
64
let mut state = State :: Idle ;
65
65
let mut widget = widget. clone ( ) ;
66
66
67
- let data = process_timewarrior_data ( & call_timewarrior ( ) . await ?) ;
67
+ let data = get_current_timewarrior_task ( ) . await ?;
68
68
if let Some ( tw) = data {
69
69
if tw. end . is_none ( ) {
70
70
// only show active tasks
@@ -126,7 +126,8 @@ struct TimewarriorRAW {
126
126
}
127
127
128
128
/// TimeWarrior entry
129
- #[ derive( Debug , PartialEq ) ]
129
+ #[ derive( Debug , PartialEq , Deserialize ) ]
130
+ #[ serde( from = "TimewarriorRAW" ) ]
130
131
struct TimewarriorData {
131
132
pub id : u32 ,
132
133
pub start : DateTime < chrono:: offset:: Utc > ,
@@ -161,24 +162,24 @@ fn format_datetime(date: &DateTime<chrono::Utc>, format: &str) -> String {
161
162
date. format ( format) . to_string ( )
162
163
}
163
164
164
- /// Execute "timew export now" and return the result
165
- async fn call_timewarrior ( ) -> Result < String > {
165
+ /// Execute "timew export now" and return the current task (if any)
166
+ async fn get_current_timewarrior_task ( ) -> Result < Option < TimewarriorData > > {
166
167
let out = Command :: new ( "timew" )
167
168
. args ( [ "export" , "now" ] )
168
169
. output ( )
169
170
. await
170
171
. error ( "failed to run timewarrior" ) ?
171
172
. stdout ;
172
- let output = std :: str :: from_utf8 ( & out)
173
- . error ( "failed to read output from timewarrior (invalid UTF-8)" ) ?
174
- . trim ( ) ;
175
- Ok ( output . to_string ( ) )
173
+ Ok ( serde_json :: from_slice :: < Vec < TimewarriorData > > ( & out)
174
+ . unwrap_or_default ( )
175
+ . into_iter ( )
176
+ . next ( ) )
176
177
}
177
178
178
179
/// Stop or continue a task
179
180
async fn stop_continue ( ) -> Result < ( ) > {
180
181
let mut execute_continue: bool = true ;
181
- if let Some ( tw) = process_timewarrior_data ( & call_timewarrior ( ) . await ?) {
182
+ if let Some ( tw) = get_current_timewarrior_task ( ) . await ? {
182
183
// we only execute continue if the current task is stopped
183
184
// i.e. has an end defined
184
185
execute_continue = tw. end . is_some ( ) ;
@@ -200,28 +201,3 @@ async fn stop_continue() -> Result<()> {
200
201
. error ( "Error executing stop/continue" )
201
202
. map ( |_| ( ) )
202
203
}
203
-
204
- /// Process the output from "timew export" and return the first entry
205
- fn process_timewarrior_data ( input : & str ) -> Option < TimewarriorData > {
206
- let t: Vec < TimewarriorRAW > = serde_json:: from_str ( input) . unwrap_or_default ( ) ;
207
- t. into_iter ( ) . next ( ) . map ( TimewarriorData :: from)
208
- }
209
-
210
- #[ cfg( test) ]
211
- mod tests {
212
- use super :: * ;
213
-
214
- #[ test]
215
- fn test_process_timewarrior_data ( ) {
216
- assert_eq ! ( process_timewarrior_data( "" ) , None , ) ;
217
-
218
- assert_eq ! ( process_timewarrior_data( "[]" ) , None , ) ;
219
-
220
- let a = process_timewarrior_data ( "[{\" id\" :1,\" start\" :\" 20230131T175754Z\" ,\" tags\" :[\" i3status\" ],\" annotation\" :\" timewarrior plugin\" }]" ) ;
221
- assert_eq ! ( a. is_some( ) , true ) ;
222
- if let Some ( b) = a {
223
- assert_eq ! ( b. id, 1 ) ;
224
- assert_eq ! ( b. end, None ) ;
225
- }
226
- }
227
- }
0 commit comments