Skip to content

Commit

Permalink
Added todo scheduling
Browse files Browse the repository at this point in the history
  • Loading branch information
nimaaskarian committed Jan 30, 2024
1 parent d034fc3 commit 10b817b
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 96 deletions.
104 changes: 104 additions & 0 deletions '
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use chrono::{Local ,NaiveDate};
use chrono::Duration;
use chrono::format::ParseError;
use scanf::sscanf;

use crate::todo_list::todo::date;

#[derive(Debug, PartialEq, Clone, Default)]
pub struct Schedule {
day: u32,
done_date: Option<NaiveDate>,
pub is_scheduled: bool,
}

struct ScheduleRest {
schedule: Schedule,
rest: String,
}

impl From<String> for ScheduleRest {

fn from(input:String) -> ScheduleRest {
let mut day = 0;
let mut date_string = String::new();
let mut is_scheduled = false;
let mut rest = String::new();
match input {
_ if sscanf!(input.as_str(), "{}[DAILY {}]", rest, date_string).is_ok() => {
day = 1;
is_scheduled = true;
}
_ if sscanf!(input.as_str(), "{}[D{} {}]", rest, day, date_string).is_ok() => {
is_scheduled = true;
}
_ => {},
};
let last_done = match date::parse(&date_string) {
Ok(value) => Some(value),
Err(_) => None
};

let schedule = Schedule {
day,
done_date: last_done,
is_scheduled
};

ScheduleRest {
schedule,
rest
}
}
}

impl Into<String> for Schedule {
fn into(self) -> String {
if self.is_scheduled {
let date_str = date::format(self.done_date);
match self.day {
1 => format!(" [DAILY {date_str}]"),
any => format!(" [D{any} {date_str}]"),
}
} else {
String::new()
}
}
}

impl Schedule {
pub fn new() -> Self {
Schedule {
day: 0,
done_date: None,
is_scheduled: false,
}
}
pub fn display(&self) -> String{
if !self.is_scheduled {
return String::new();
}
let last_save = if let Some(done_date) = self.done_date {
date::current() - done_date
} else {
Duration::zero()
};
let inner_str = match last_save.num_days() {
0 => String::new(),
1 => String::from(", last done yesterday"),
any => format!(", last done {} days ago", any)
};
match self.day {
1 =>format!(" (Daily{inner_str})"),
day =>format!(" (Each {} day {inner_str})", self.day),
}

format!(" (Each {} day {inner_str})", self.day)
}

pub fn match_message(input: &mut String) -> Self {
let ScheduleRest { schedule, rest } = ScheduleRest::from(input.clone());
input.clone_from(&rest);
schedule
}
}
20 changes: 8 additions & 12 deletions src/todo_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,15 @@ impl TodoList {
display_list
}

pub fn read (filename: &PathBuf, read_dependencies: bool, is_root: bool) -> Self{
let dependency_path = if is_root {
pub fn dependency_parent(filename: &PathBuf, is_root: bool) -> PathBuf {
if is_root {
filename.parent().unwrap().to_path_buf().join("notes")
} else {
filename.parent().unwrap().to_path_buf()
};
}
}

pub fn read (filename: &PathBuf, read_dependencies: bool, is_root: bool) -> Self{
let mut todo_list = Self::new();
if !filename.is_file() {
return todo_list
Expand All @@ -239,12 +242,13 @@ impl TodoList {
todo_list.undone.sort();
todo_list.done.sort();
if read_dependencies {
let dependency_path = Self::dependency_parent(filename, is_root);
todo_list.read_dependencies(&dependency_path)
}
return todo_list
}

pub fn read_dependencies(&mut self, path: &PathBuf) {
fn read_dependencies(&mut self, path: &PathBuf) {
let mut todos = [&mut self.undone.todos, &mut self.done.todos];

for todo in todos.iter_mut().flat_map(|v| v.iter_mut()) {
Expand Down Expand Up @@ -435,12 +439,4 @@ mod tests {

assert_eq!(todo_list, sorted_list)
}

#[test]
fn test_something() {
let todo_path = todo_path().unwrap();
let mut todo_list = TodoList::read(&todo_path, true, true);
let mut output = vec![];
println!("{:?}", todo_list.all_dependent_files(&todo_path, &mut output));
}
}
130 changes: 50 additions & 80 deletions src/todo_list/todo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use scanf::sscanf;
// }}}
// mod{{{
mod note;
mod date;
mod schedule;
use schedule::Schedule;
use note::{sha1, open_temp_editor};

use super::TodoList;
Expand All @@ -32,8 +33,7 @@ pub struct Todo {
dependency_type: DependencyType,
done:bool,
removed_names: Vec<String>,
daily: bool,
date_str: String,
schedule: Schedule,
}

impl Into<String> for &Todo {
Expand All @@ -43,12 +43,9 @@ impl Into<String> for &Todo {
DependencyType::None => String::new(),
_ => format!(">{}", self.dependency_name),
};
let daily_str = if self.daily {
format!(" [DAILY {}]", self.date_str)
} else {
String::new()
};
format!("[{done_str}{}]{note_str} {}{daily_str}", self.priority, self.message)
let schedule_str:String =(&self.schedule).into();

format!("[{done_str}{}]{note_str} {}{schedule_str}", self.priority, self.message)
}
}

Expand Down Expand Up @@ -77,27 +74,25 @@ impl TryFrom<&str> for Todo {
let mut priority_string:String = String::new();
let mut dependency_type = DependencyType::None;
let mut dependency_name = String::new();

if sscanf!(input,"[{}]>{}.todo {}", priority_string, dependency_name, message).is_err() {
if sscanf!(input,"[{}]>{} {}", priority_string, dependency_name, message).is_err() {
if sscanf!(input,"[{}] {}", priority_string, message).is_err() {
return Err(TodoError::ReadFailed);
}
match input {
_ if sscanf!(input, "[{}]>{}.todo {}", priority_string, dependency_name, message).is_ok() => {
dependency_type = DependencyType::TodoList;
}
} else {
dependency_type = DependencyType::TodoList;
_ if sscanf!(input, "[{}]>{} {}", priority_string, dependency_name, message).is_ok() => {
dependency_type = DependencyType::Note;
}
_ if sscanf!(input, "[{}] {}", priority_string, message).is_ok() => {
dependency_type = DependencyType::None;
}
_ => return Err(TodoError::ReadFailed),
}

if dependency_type == DependencyType::None && !dependency_name.is_empty() {
dependency_type = DependencyType::Note;
}
let dependencies = TodoList::new();
let dependency_name = match dependency_type {
DependencyType::None => String::new(),
DependencyType::TodoList => Self::todolist_name(&dependency_name),
DependencyType::Note => dependency_name,
};
let mut done = priority_string.chars().nth(0).unwrap() == '-';

let priority:i8 = match priority_string.parse() {
Ok(value) => {
Expand All @@ -109,34 +104,16 @@ impl TryFrom<&str> for Todo {
Err(_) => 0
};

let daily = if sscanf!(message.clone().as_str(), "{}[DAILY {}]", message, date_string).is_ok() {
if let Ok(date) = date::parse(&date_string) {
let current_date = date::current();
if current_date > date {
done = false
}
}
true
} else {
false
};

let date_str = if daily {
if done {
date::current_str()
} else {
date_string
}
} else {
String::new()
};

let schedule = Schedule::match_message(&mut message);
let mut done = priority_string.chars().nth(0).unwrap() == '-';

if schedule.should_undone() {
done = false;
}
Ok(Todo {
note: String::new(),
dependency_type,
date_str,
daily,
schedule,
removed_names: Vec::new(),
dependency_name,
dependencies,
Expand All @@ -158,8 +135,7 @@ impl Todo {
Todo {
note: String::new(),
dependency_type: DependencyType::None,
date_str: String::new(),
daily: false,
schedule: Schedule::new(),
removed_names: Vec::new(),
dependency_name: String::new(),
dependencies: TodoList::new(),
Expand Down Expand Up @@ -270,31 +246,13 @@ impl Todo {
DependencyType::Note => ">",
DependencyType::TodoList => "-",
};
let daily_str = if self.daily {
let inner_str = if self.date_str.is_empty() {
String::new()
} else {
let last_save = if let Ok(parsed_date) = date::parse(&self.date_str) {
date::current() - parsed_date
} else {
Duration::zero()
};
match last_save.num_days() {
0 => String::new(),
1 => String::from(", last done yesterday"),
any => format!(", last done {} days ago", any)
}
};
format!(" (Daily{inner_str})")
} else {
String::new()
};
let daily_str = self.schedule.display();
format!("{done_string}{}{note_string} {}{daily_str}", self.priority, self.message)
}

pub fn dependency_path(&self ,path : &PathBuf) -> Option<PathBuf>{
pub fn dependency_path(&self ,path: &PathBuf) -> Option<PathBuf>{
match path.parent() {
Some(path) => Some(path.to_path_buf().join("notes").join(&self.dependency_name).clone()),
Some(path) => Some(TodoList::dependency_parent(&path.to_path_buf(), false)),
None => None,
}
}
Expand Down Expand Up @@ -346,15 +304,28 @@ impl Todo {

#[inline]
pub fn toggle_daily(&mut self) {
self.daily = !self.daily;
self.schedule.toggle();
self.schedule.set_daily();
}

#[inline]
pub fn toggle_weekly(&mut self) {
self.schedule.toggle();
self.schedule.set_weekly();
}

#[inline]
pub fn enable_day(&mut self, day: i64) {
self.schedule.enable();
self.schedule.set_day(day);
}

#[inline]
pub fn set_done(&mut self, done:bool) {
if self.daily && done {
self.date_str = date::current_str();
if done {
self.schedule.current_date()
} else {
self.date_str = String::new();
self.schedule.none_date()
}
self.done = done;
}
Expand Down Expand Up @@ -435,8 +406,7 @@ mod tests {
let expected = Ok(Todo {
note: String::new(),
dependency_type: DependencyType::Note,
date_str: String::new(),
daily: false,
schedule: Schedule::new(),
removed_names: Vec::new(),
dependency_name: String::from("2c924e3088204ee77ba681f72be3444357932fca"),
message: "Test".to_string(),
Expand Down Expand Up @@ -549,8 +519,7 @@ mod tests {
let expected = Todo {
note: String::new(),
dependency_type: DependencyType::TodoList,
date_str: String::new(),
daily: false,
schedule: Schedule::new(),
removed_names: Vec::new(),
dependency_name: "1BE348656D84993A6DF0DB0DECF2E95EF2CF461c.todo".to_string(),
message: "Read for exams".to_string(),
Expand All @@ -568,8 +537,7 @@ mod tests {
let expected = Todo {
note: String::new(),
dependency_type: DependencyType::None,
date_str: "2023-09-05".to_string(),
daily: true,
schedule: Schedule::from("DAILY 2023-09-05"),
removed_names: Vec::new(),
dependency_name: String::new(),
message: "this one should be daily".to_string(),
Expand All @@ -581,12 +549,14 @@ mod tests {
let input = "[2] this one should be daily [DAILY 2023-09-05]";
let todo = Todo::try_from(input).unwrap();
assert_eq!(todo, expected);
}

#[test]
fn test_daily_display() {
let test = Todo {
note: String::new(),
dependency_type: DependencyType::None,
date_str: String::new(),
daily: true,
schedule: Schedule::from("DAILY"),
removed_names: Vec::new(),
dependency_name: String::new(),
message: "this one should be daily".to_string(),
Expand Down
Loading

0 comments on commit 10b817b

Please sign in to comment.