From 1d261fef33994466aeeaf3b7703037e525d1418d Mon Sep 17 00:00:00 2001 From: JF Ding Date: Fri, 27 Dec 2024 00:37:36 +0800 Subject: [PATCH 1/3] add new routine type: once for one-shot reminder --- docs/routine-tasks-v1.md | 67 ------------------- docs/routine-tasks-v2.md | 63 ----------------- .../{routine-tasks-v3.md => routine-tasks.md} | 4 +- src/cli.rs | 1 + src/taskbox.rs | 6 +- src/util.rs | 16 ++--- 6 files changed, 16 insertions(+), 141 deletions(-) delete mode 100644 docs/routine-tasks-v1.md delete mode 100644 docs/routine-tasks-v2.md rename docs/{routine-tasks-v3.md => routine-tasks.md} (96%) diff --git a/docs/routine-tasks-v1.md b/docs/routine-tasks-v1.md deleted file mode 100644 index d10673d..0000000 --- a/docs/routine-tasks-v1.md +++ /dev/null @@ -1,67 +0,0 @@ -# Design of routine tasks - -## Types of routine tasks -1. daily -2. weekly -3. bi-weekly -4. monthly-on-date -5. monthly-on-weekday (4 weeks) - -## How to mark them in markdown -- [d] daily - - [D] daily (done) -- [w] weekly - - [W] weekly (done) -- [b] bi-weekly - - [B] bi-weekly (done) -- [q] monthly-on-weekday - - [Q] monthly-on-weekday (done) -- [m] monthly-on-date - - [M] monthly-on-date (done) - -## How to operate on them -* normally, routine tasks should be added into "today" or "tomorrow" box, and "INBOX" can have *daily* tasks -* when to run `today` cli with any command, will have a daily-once hook to check the routine tasks in old days boxes, in the logic: -``` -check if found belows: - "daily" in yesterday - "weekly" in the day of a week ago - "biweekly" in the day of 2 weeks ago - "monthly-on-weekday" in the day of 4 weeks ago - "monthly-on-date" in the day of last monthly -then: - create a new one(same) in today - if previous one is done: - mark it as normal done ([x]) - else: - mark the found one as normal undone([ ]) - -``` -* for `add`, options are: - * `-d/--daily` - * `-w/--weekly` - * `-b/--biweekly` - * `-q/--qweekly` - * `-m/--monthly` -* or we can add it firstly and modify it later by command `edit` -* for `mark` command, just change the routine flag char to upper case -* for `count`, count in the routine ones -* for `import`, will import the matched routine tasks -* for `list` and `listall`, list them with special flag chars -* for `collect` command(INBOX/other -> today), only collect the *daily* tasks, and clear INBOX -* for `pool` command(today -> INBOX), will NOT pooling routine tasks to INBOX -* for `shift` command(today -> tomorrow), will clone a _normal_ task to tomorrow and today unchanged -* [ :sparkles: ] for `sink` command(old days -> today), when scanning old days boxes, in reverse order: -``` -if found a routine task: - if it matched to today: - create a new item in today - if done: - and mark it as normal done ([x]) - else: - and mark it as normal undone ([ ]) - -``` -* no affect: `purge`, `browse`, `listbox` - - diff --git a/docs/routine-tasks-v2.md b/docs/routine-tasks-v2.md deleted file mode 100644 index 58257e1..0000000 --- a/docs/routine-tasks-v2.md +++ /dev/null @@ -1,63 +0,0 @@ -# Design of routine tasks - -## Types of routine tasks -1. daily -2. weekly -3. bi-weekly -4. monthly-on-date -5. monthly-on-weekday (4 weeks) - -## How to store them in markdown -- [d] [yyyy-mm-dd] daily - - [D] [yyyy-mm-dd] daily (done) -- [w] [yyyy-mm-dd] weekly - - [W] [yyyy-mm-dd] weekly (done) -- [b] [yyyy-mm-dd] bi-weekly - - [B] [yyyy-mm-dd] bi-weekly (done) -- [q] [yyyy-mm-dd] monthly-on-weekday - - [Q] [yyyy-mm-dd] monthly-on-weekday (done) -- [m] [yyyy-mm-dd] monthly-on-date - - [M] [yyyy-mm-dd] monthly-on-date (done) -- [m] [yyyy-mm-dd] monthly-on-date - - [M] [yyyy-mm-dd] monthly-on-date (done) -- [o] outdated task - - [O] outdated task (done) - -## Where to save -There will be a dedicated taskbox file, named `ROUTINES.md`, and the structure will be: -``` -# ROUTINES - -## daily -- [d] [2024-08-21] daily task one -- [D] [2024-08-21] daily task two (done, or stopped) - -## weekly -- [w] [2024-08-21] weekly task one -- [b] [2024-08-21] bi-weekly task two -- [q] [2024-08-21] four-weekly task three - -## monthly -- [m] [2024-08-21] monthly task one - -``` - -## How to operate on them -* use `add` command to add a new routine task with option, and it will be store in ROUTINES md file with proper flag char and current date, available options are: - * `-d/--daily` - * `-w/--weekly` - * `-b/--biweekly` - * `-q/--qweekly` - * `-m/--monthly` -* add a new command `check` to pick up any matched routine tasks to "today" box, still with routine flag chars, to strip original date and append today date as flag `--date` does -* when to run `today` cli with any command, will have a daily-once hook to run `check` -* command `edit` will have a new flag `-r/--routine` to edit the routine tasks -* for `mark` command, just change the routine flag char to upper case, means done for this time -* for `count`, count in the routine ones -* for `import`, will ignore the (exceptional)matched routine tasks -* for `list` and `listall`, list them with special flag chars -* for `collect` (INBOX/other -> today) and `pool` (today -> INBOX) will ignore the routine tasks -* for `shift` (today -> tomorrow) and `sink` (old days -> today), will ignore the _daily_ tasks, but move the other routines tasks as _outdated_ tasks with flag char "o" - * but if move from tomorrow back to today, will re-check the routine tasks (if not found, still keep [o]) -* no affect: `purge`, `browse`, `listbox` -* (optional) new cmd `routines` to list all the routine tasks diff --git a/docs/routine-tasks-v3.md b/docs/routine-tasks.md similarity index 96% rename from docs/routine-tasks-v3.md rename to docs/routine-tasks.md index 3ea4716..f30fada 100644 --- a/docs/routine-tasks-v3.md +++ b/docs/routine-tasks.md @@ -6,6 +6,7 @@ 3. bi-weekly 4. monthly-on-date 5. monthly-on-weekday (4 weeks) +6. once (one-shot reminder) ## How to store them in markdown - [ ] {󰃵:d yyyy-mm-dd} daily @@ -13,6 +14,7 @@ - [ ] {󰃵:b yyyy-mm-dd} bi-weekly - [ ] {󰃵:q yyyy-mm-dd} monthly-on-weekday - [ ] {󰃵:m yyyy-mm-dd} monthly-on-date +- [ ] {󰃵:1 yyyy-mm-dd} reminder ## Where to save There will be a dedicated taskbox file, named `ROUTINES.md`, and the structure will be: @@ -35,7 +37,7 @@ There will be a dedicated taskbox file, named `ROUTINES.md`, and the structure w ## How to operate on them * use `add` command to add a new routine task with option, and it will be store in ROUTINES md file with proper *routine-prefix* and current date, available options are: - * `-r/--routine ` + * `-r/--routine ` * add a new command `checkout` to pick up any matched routine tasks to "today" box, with expanded routine info (means "checkout") * actually its an alias of `collect --inbox routines` * when to run `today` cli with any command, will have a daily-once hook to run `checkout` diff --git a/src/cli.rs b/src/cli.rs index d720cf2..01fbb9a 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -29,6 +29,7 @@ pub enum Routine { Biweekly, Qweekly, Monthly, + Once, } #[derive(Debug, Clone, Subcommand)] diff --git a/src/taskbox.rs b/src/taskbox.rs index 3d65a98..3f732f5 100644 --- a/src/taskbox.rs +++ b/src/taskbox.rs @@ -17,9 +17,9 @@ lazy_static! { static ref RE_PREFIX_OPEN :Regex = Regex::new(r"^- \[[ ]\] (.*)").unwrap(); static ref RE_PREFIX_DONE :Regex = Regex::new(r"^- \[[xX\-/<>\*]\] (.*)").unwrap(); static ref RE_ROUTINES :Regex = - Regex::new(r"\{󰃯:([dDwWbBqQmM]) (\d{4}-\d{2}-\d{2})\w{3} 󰳟\} (.*)").unwrap(); + Regex::new(r"\{󰃯:([dDwWbBqQmM1]) (\d{4}-\d{2}-\d{2})\w{3} 󰳟\} (.*)").unwrap(); static ref RE_ROUTINES_CHECKOUT :Regex = - Regex::new(r"\{󰃯:(daily|weekly|biweekly|qweekly|monthly)\} (.*)").unwrap(); + Regex::new(r"\{󰃯:(daily|weekly|biweekly|qweekly|monthly|reminder)\} (.*)").unwrap(); } pub const INBOX_BOXNAME :&str = "INBOX"; @@ -277,6 +277,7 @@ impl TaskBox { "b" => "biweekly", "q" => "qweekly", "m" => "monthly", + "1" => "reminder", _ => "unknown", }; let checkout_date = match to.as_ref() { @@ -351,6 +352,7 @@ impl TaskBox { Routine::Biweekly => "b", Routine::Qweekly => "q", Routine::Monthly => "m", + Routine::Once => "1", }, start_date, weekday_from_date(start_date), diff --git a/src/util.rs b/src/util.rs index e2e595d..ec0ddc6 100644 --- a/src/util.rs +++ b/src/util.rs @@ -62,8 +62,8 @@ pub fn weekday_from_date(date_str: &str) -> String { NaiveDate::parse_from_str(date_str, "%Y-%m-%d").unwrap().weekday().to_string() } -pub fn match_routine(kind: &str, s_date_str: &str, match_to: &str) -> bool { - let mut s_date = NaiveDate::parse_from_str(s_date_str, "%Y-%m-%d").unwrap(); +pub fn match_routine(kind: &str, start_date_str: &str, match_to: &str) -> bool { + let mut closest_date = NaiveDate::parse_from_str(start_date_str, "%Y-%m-%d").unwrap(); let match_to_date = match match_to { "today" => Local::now().date_naive(), "yesterday" => Local::now().add(chrono::Duration::days(-1)).date_naive(), @@ -72,23 +72,23 @@ pub fn match_routine(kind: &str, s_date_str: &str, match_to: &str) -> bool { }; if kind == "m" { - while s_date < match_to_date { - s_date = s_date + chrono::Months::new(1); + while closest_date < match_to_date { + closest_date = closest_date + chrono::Months::new(1); } } else { let steps = match kind { - "d" => 1, + "d" | "1" => 1, "w" => 7, "b" => 14, "q" => 28, _ => panic!("unknown routine kind"), }; - while s_date < match_to_date { - s_date += chrono::Duration::days(steps); + while closest_date < match_to_date { + closest_date += chrono::Duration::days(steps); } } - s_date == match_to_date + closest_date == match_to_date } pub fn get_box_alias(name_in: &str) -> String { From ba2dae81654b05a652c1912fdda2e87f8f4acf88 Mon Sep 17 00:00:00 2001 From: JF Ding Date: Fri, 27 Dec 2024 00:53:52 +0800 Subject: [PATCH 2/3] cleanup reminder from routines box after checkout --- src/taskbox.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/taskbox.rs b/src/taskbox.rs index 3f732f5..934a335 100644 --- a/src/taskbox.rs +++ b/src/taskbox.rs @@ -294,6 +294,11 @@ impl TaskBox { if ! self.tasks.contains(&pair) { self.tasks.push(pair) } + + // clean up "once reminder" + if kind == "reminder" { + tb_from.tasks.retain(|(_task, _)| _task != &task) + } } else { // ignore non-routine task println!("{} {} : {} {}", @@ -330,10 +335,7 @@ impl TaskBox { } } - // "ROUTINES" not drain - if from != ROUTINE_BOXNAME { - tb_from._dump().unwrap(); - } + tb_from._dump().unwrap(); self._dump().unwrap(); } From 902f856aff3c30a16ff88cef2eeb8de137932fd3 Mon Sep 17 00:00:00 2001 From: JF Ding Date: Fri, 27 Dec 2024 01:11:49 +0800 Subject: [PATCH 3/3] update test cases for reminder type items --- tests/taskbox.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/taskbox.rs b/tests/taskbox.rs index 624a076..26b5e25 100644 --- a/tests/taskbox.rs +++ b/tests/taskbox.rs @@ -199,7 +199,7 @@ fn test_collect_from_with_sub_done() { - [ ] Task2 to move - [ ] Task3 to move but keep with "done" status - [ ] SubTask1 to move -- [ ] 󰼈 Task5 to move with warning icon +- [ ]  Task5 to move with warning icon - [ ] SubTask1 to move - [ ] SubTask3 to move "#; @@ -255,7 +255,7 @@ fn test_collect_from_with_dup_sub() { - [ ] Task2 to move - [ ] SubTask1 to move - [ ] Task3 to move -- [ ] 󰼈 Task4 to move +- [ ]  Task4 to move - [ ] SubTask1 to move "#; @@ -290,28 +290,40 @@ fn test_checkout() { let mut routine = tb.sibling("routine"); routine.add("Daily routine".to_string(), Some(Routine::Daily), false, &get_today()); + + // two reminders + routine.add("reminder today".to_string(), Some(Routine::Once), false, &get_today()); + routine.add("reminder tomorrow".to_string(), Some(Routine::Once), false, &get_tomorrow()); + routine.add("ignore not routine".to_string(), None, false, ""); routine.load(); - assert_eq!(routine.tasks.len(), 2); + assert_eq!(routine.tasks.len(), 4); assert!(routine.tasks[0].0.starts_with("{󰃯:d ")); assert!(routine.tasks[0].0.ends_with("} Daily routine")); + assert!(routine.tasks[1].0.starts_with("{󰃯:1 ")); + assert!(routine.tasks[1].0.ends_with("} reminder today")); + assert!(routine.tasks[2].0.starts_with("{󰃯:1 ")); + assert!(routine.tasks[2].0.ends_with("} reminder tomorrow")); today.collect_from(&mut routine); today.load(); - assert_eq!(today.tasks.len(), 1); + assert_eq!(today.tasks.len(), 2); assert!(today.tasks[0].0.starts_with("{󰃯:daily} ")); assert!(today.tasks[0].0.contains("} Daily routine")); assert!(today.tasks[0].0.contains(" [󰴹 ")); + assert!(today.tasks[1].0.starts_with("{󰃯:reminder} ")); + assert!(today.tasks[1].0.contains("} reminder today")); + assert!(today.tasks[1].0.contains(" [󰴹 ")); + tb.collect_from(&mut routine); tb.load(); assert_eq!(tb.tasks.len(), 0); - today.collect_from(&mut routine); - today.load(); - assert_eq!(today.tasks.len(), 1); + routine.load(); + assert_eq!(routine.tasks.len(), 3); } #[test]