Compare commits

...

2 Commits

Author SHA1 Message Date
Andrei Stoica 16a2646cb8 updated config path 2023-06-25 06:59:53 -04:00
Andrei Stoica 86750a7428 todo module refactor 2023-06-25 06:58:08 -04:00
5 changed files with 138 additions and 136 deletions

View File

@ -66,7 +66,6 @@ impl Config {
home_cfg.push(format!(".{}", cfg_name));
let mut pwd_cfg = PathBuf::from(pwd.clone());
pwd_cfg.push(cfg_name);
pwd_cfg.push(format!(".{}", cfg_name));
Ok(vec![home_config_cfg, home_cfg, pwd_cfg])

View File

@ -3,7 +3,7 @@ mod todo;
use crate::config::Config;
use crate::todo::{Status as TaskStatus, TaskGroup};
use crate::todo::file::TodoFile;
use crate::todo::File as TodoFile;
use chrono::naive::NaiveDate;
use chrono::{Datelike, Local};
use comrak::nodes::{AstNode, NodeValue};

View File

@ -5,12 +5,12 @@ use std::fs::DirEntry;
use std::str::FromStr;
#[derive(Debug)]
pub struct TodoFile {
pub struct File {
pub file: DirEntry,
pub date: NaiveDate,
}
impl TodoFile {
impl File {
fn capture_as_number<T: FromStr>(capture: &regex::Captures, name: &str) -> Result<T, String> {
Ok(capture
.name(name)
@ -21,7 +21,7 @@ impl TodoFile {
.ok_or("Something went wrong".to_owned())?)
}
pub fn latest_file(a: TodoFile, b: TodoFile) -> TodoFile {
pub fn latest_file(a: File, b: File) -> File {
if a.date > b.date {
a
} else {
@ -36,11 +36,11 @@ impl TodoFile {
}
}
impl TryFrom<DirEntry> for TodoFile {
impl TryFrom<DirEntry> for File {
type Error = String;
fn try_from(direntry: DirEntry) -> Result<Self, Self::Error> {
let re = TodoFile::get_file_regex();
let re = File::get_file_regex();
// println!("{:?}", re);
let file_name = direntry.file_name();
let file_name_str = match file_name.to_str() {

View File

@ -1,130 +1,5 @@
pub mod file;
mod file;
mod tasks;
use std::borrow::Borrow;
use comrak::nodes::AstNode;
use comrak::nodes::NodeValue;
#[derive(Debug, Clone)]
pub struct TaskGroup {
pub name: String,
pub tasks: Vec<Task>,
pub level: u8,
}
// This does not support subtasks, need to figure out best path forward
#[derive(Debug, Clone)]
pub struct Task {
pub status: Status,
pub text: String,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Status {
Done(char),
Todo(char),
Empty,
}
impl Task {
fn find_text<'a>(node: &'a AstNode<'a>) -> String {
let mut text = String::new();
for child in node.descendants() {
let data_ref = child.data.borrow();
if let NodeValue::Text(contents) = &data_ref.value {
text.push_str(format!("{}\n ", &contents.clone()).as_str());
};
}
text
}
}
impl ToString for Task {
fn to_string(&self) -> String {
let ch = match self.status {
Status::Done(ch) => ch,
Status::Todo(ch) => ch,
Status::Empty => ' ',
};
format!(" - [{}] {}\n", ch, self.text.trim())
}
}
impl<'a> TryFrom<&'a AstNode<'a>> for Task {
type Error = String;
fn try_from(node: &'a AstNode<'a>) -> Result<Self, Self::Error> {
let data_ref = &node.data.borrow();
if let NodeValue::TaskItem(ch) = data_ref.value {
let text = Self::find_text(node);
let status = match ch {
Some(c) if c == 'x' || c == 'X' => Status::Done(c),
Some(c) => Status::Todo(c),
_ => Status::Empty,
};
Ok(Self { status, text })
} else {
Err("Node being parsed is not a TaskItem".into())
}
}
}
impl TaskGroup {
pub fn empty(name: String, level: u8) -> TaskGroup {
TaskGroup {
name,
tasks: Vec::new(),
level,
}
}
}
impl ToString for TaskGroup {
fn to_string(&self) -> String {
let mut output = String::new();
output.push_str(format!("{} {}\n", "#".repeat(self.level.into()), self.name).as_str());
self.tasks
.iter()
.for_each(|task| output.push_str(task.to_string().as_str()));
output
}
}
impl<'a> TryFrom<&'a AstNode<'a>> for TaskGroup {
type Error = String;
fn try_from(node: &'a AstNode<'a>) -> Result<Self, Self::Error> {
let node_ref = &node.data.borrow();
if let NodeValue::Heading(heading) = node_ref.value {
let level = heading.level;
let first_child_ref = &node.first_child();
let first_child = if let Some(child) = first_child_ref.borrow() {
child
} else {
return Err("".into());
};
let data_ref = &first_child.data.borrow();
let name = if let NodeValue::Text(value) = &data_ref.value {
value.to_string()
} else {
return Err("".into());
};
let next_sib = node.next_sibling().ok_or("Empty section at end of file")?;
if let NodeValue::List(_list_meta) = next_sib.data.borrow().value {
let tasks = next_sib
.children()
.into_iter()
.filter_map(|item_node| Task::try_from(item_node).ok())
.collect();
Ok(TaskGroup { name, tasks, level })
} else {
Err("Next sibling of node is not a list".into())
}
} else {
Err("Node is not a section heading".into())
}
}
}
pub use file::File;
pub use tasks::{Status, Task, TaskGroup};

128
src/todo/tasks.rs Normal file
View File

@ -0,0 +1,128 @@
use std::borrow::Borrow;
use comrak::nodes::AstNode;
use comrak::nodes::NodeValue;
#[derive(Debug, Clone)]
pub struct TaskGroup {
pub name: String,
pub tasks: Vec<Task>,
pub level: u8,
}
// This does not support subtasks, need to figure out best path forward
#[derive(Debug, Clone)]
pub struct Task {
pub status: Status,
pub text: String,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Status {
Done(char),
Todo(char),
Empty,
}
impl Task {
fn find_text<'a>(node: &'a AstNode<'a>) -> String {
let mut text = String::new();
for child in node.descendants() {
let data_ref = child.data.borrow();
if let NodeValue::Text(contents) = &data_ref.value {
text.push_str(format!("{}\n ", &contents.clone()).as_str());
};
}
text
}
}
impl ToString for Task {
fn to_string(&self) -> String {
let ch = match self.status {
Status::Done(ch) => ch,
Status::Todo(ch) => ch,
Status::Empty => ' ',
};
format!(" - [{}] {}\n", ch, self.text.trim())
}
}
impl<'a> TryFrom<&'a AstNode<'a>> for Task {
type Error = String;
fn try_from(node: &'a AstNode<'a>) -> Result<Self, Self::Error> {
let data_ref = &node.data.borrow();
if let NodeValue::TaskItem(ch) = data_ref.value {
let text = Self::find_text(node);
let status = match ch {
Some(c) if c == 'x' || c == 'X' => Status::Done(c),
Some(c) => Status::Todo(c),
_ => Status::Empty,
};
Ok(Self { status, text })
} else {
Err("Node being parsed is not a TaskItem".into())
}
}
}
impl TaskGroup {
pub fn empty(name: String, level: u8) -> TaskGroup {
TaskGroup {
name,
tasks: Vec::new(),
level,
}
}
}
impl ToString for TaskGroup {
fn to_string(&self) -> String {
let mut output = String::new();
output.push_str(format!("{} {}\n", "#".repeat(self.level.into()), self.name).as_str());
self.tasks
.iter()
.for_each(|task| output.push_str(task.to_string().as_str()));
output
}
}
impl<'a> TryFrom<&'a AstNode<'a>> for TaskGroup {
type Error = String;
fn try_from(node: &'a AstNode<'a>) -> Result<Self, Self::Error> {
let node_ref = &node.data.borrow();
if let NodeValue::Heading(heading) = node_ref.value {
let level = heading.level;
let first_child_ref = &node.first_child();
let first_child = if let Some(child) = first_child_ref.borrow() {
child
} else {
return Err("".into());
};
let data_ref = &first_child.data.borrow();
let name = if let NodeValue::Text(value) = &data_ref.value {
value.to_string()
} else {
return Err("".into());
};
let next_sib = node.next_sibling().ok_or("Empty section at end of file")?;
if let NodeValue::List(_list_meta) = next_sib.data.borrow().value {
let tasks = next_sib
.children()
.into_iter()
.filter_map(|item_node| Task::try_from(item_node).ok())
.collect();
Ok(TaskGroup { name, tasks, level })
} else {
Err("Next sibling of node is not a list".into())
}
} else {
Err("Node is not a section heading".into())
}
}
}