diff --git a/README.md b/README.md index 05744f3..63ab540 100644 --- a/README.md +++ b/README.md @@ -100,9 +100,10 @@ when the application is terminated regularly. Dots can be repeated to move to parent tasks. - `:[IND][COL]` - add property column COL at IND or end, if it already exists remove property column COL or IND -- `>[TEXT]` - Complete active task and move to parent, with optional state description -- `<[TEXT]` - Close active task and move to parent, with optional state description -- `!TEXT` - Set state for current task from text +- `*[TIME]` - add timetracking with the specified offset +- `>[TEXT]` - complete active task and move to parent, with optional state description +- `<[TEXT]` - close active task and move to parent, with optional state description +- `!TEXT` - set state for current task from text - `,TEXT` - add text note (comment / description) - `@` - undoes last action (moving in place or upwards or waiting a minute confirms pending actions) diff --git a/src/main.rs b/src/main.rs index 59a7cbe..c4f9ad8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,12 +10,13 @@ use std::str::FromStr; use std::sync::mpsc; use std::sync::mpsc::Sender; +use chrono::DateTime; use colored::Colorize; use log::{debug, error, info, trace, warn}; use nostr_sdk::prelude::*; use xdg::BaseDirectories; -use crate::kinds::{build_tracking, TRACKING_KIND}; +use crate::kinds::TRACKING_KIND; use crate::task::State; use crate::tasks::Tasks; @@ -352,7 +353,17 @@ async fn main() { } Some('-') => { - tasks.remove_tag(arg.to_string()) + tasks.remove_tag(arg.to_string()); + } + + Some('*') => { + if let Ok(num) = arg.parse::() { + tasks.track_at(Timestamp::now() + num); + } else if let Ok(date) = DateTime::parse_from_rfc3339(arg) { + tasks.track_at(Timestamp::from(date.to_utc().timestamp() as u64)); + } else { + warn!("Cannot parse {arg}"); + } } Some('.') => { diff --git a/src/tasks.rs b/src/tasks.rs index 346e3de..89abedd 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -495,6 +495,18 @@ impl Tasks { ) } + fn get_task_title(&self, id: &EventId) -> String { + self.tasks.get(id).map_or(id.to_string(), |t| t.get_title()) + } + + pub(crate) fn track_at(&mut self, time: Timestamp) -> EventId { + info!("Tracking \"{:?}\" from {}", self.position.map(|id| self.get_task_title(&id)), time.to_human_datetime()); + self.submit( + build_tracking(self.get_position()) + .custom_created_at(time) + ) + } + fn submit(&mut self, builder: EventBuilder) -> EventId { let event = self.sender.submit(builder).unwrap(); let id = event.id;