3 Commits

Author SHA1 Message Date
fc7e45cd3f test coverage 2024-04-02 00:07:09 -04:00
9fe6ae5eb8 listing all files 2024-04-01 22:00:40 -04:00
ddd620a021 code cleanup
mostly dead code removal
some formating
2024-04-01 13:25:04 -04:00
6 changed files with 112 additions and 59 deletions

View File

@@ -17,6 +17,9 @@ pub struct Args {
/// list closest files to date
#[arg(short, long)]
pub list: bool,
/// number of files to list
#[arg(short, long, default_value_t = 5)]
pub number: usize,
/// list closest files to date
#[arg(short = 'L', long)]
pub list_all: bool,

View File

@@ -111,3 +111,101 @@ pub fn extract_secitons<'a>(
}
groups
}
#[cfg(test)]
mod test {
use super::*;
use crate::todo::Task;
#[test]
fn test_extract_sections() {
let test_md = "\
# Test
## Content
- [ ] something
- [x] done
- [!] other
## Unused
### Sub section
- [ ] task
## Unrealated Stuff
- [ ] something else
+ [ ] subtask";
let arena = Arena::new();
let root = parse_todo_file(&test_md.to_string(), &arena);
let result = extract_secitons(root, &vec![]);
assert_eq!(result.keys().count(), 0);
let result = extract_secitons(root, &vec!["Not There".to_string()]);
assert_eq!(result.keys().count(), 0);
let sections = vec!["Unused".to_string()];
let result = extract_secitons(root, &sections);
assert_eq!(result.keys().count(), 0);
let sections = vec!["Sub section".to_string()];
let result = extract_secitons(root, &sections);
println!("{:#?}", root);
assert_eq!(result.keys().count(), 1);
assert!(result.get(sections.first().unwrap()).is_some());
assert_eq!(result.get(sections.first().unwrap()).unwrap().level, 3);
let sections = vec!["Content".to_string()];
let result = extract_secitons(root, &sections);
println!("{:#?}", root);
assert_eq!(result.keys().count(), 1);
assert!(result.get(sections.first().unwrap()).is_some());
assert_eq!(
result
.get(sections.first().unwrap())
.expect("No Value for \"Content\""),
&TaskGroup {
name: sections.first().unwrap().clone(),
tasks: vec![
Task {
status: TaskStatus::Empty,
text: "something".to_string(),
subtasks: None
},
Task {
status: TaskStatus::Todo('!'),
text: "other".to_string(),
subtasks: None
},
],
level: 2
}
);
let sections = vec!["Unrealated Stuff".to_string()];
let result = extract_secitons(root, &sections);
assert_eq!(result.keys().count(), 1);
assert!(result.get(sections.first().unwrap()).is_some());
assert_eq!(
result
.get(sections.first().unwrap())
.expect("No Value for \"Content\""),
&TaskGroup {
name: sections.first().unwrap().clone(),
tasks: vec![Task {
status: TaskStatus::Empty,
text: "something else".to_string(),
subtasks: Some(vec![Task {
status: TaskStatus::Empty,
text: "subtask".to_string(),
subtasks: None
}]),
}],
level: 2
}
);
let result = extract_secitons(
root,
&vec!["Content".to_string(), "Sub section".to_string()],
);
assert_eq!(result.keys().count(), 2);
}
}

View File

@@ -79,7 +79,11 @@ fn main() {
let today = Local::now().date_naive();
let target = today - TimeDelta::try_days(args.previous.into()).unwrap();
let closest_files = TodoFile::get_closest_files(files.collect(), target, 5);
if args.list_all {
files.for_each(|f| println!("{}", f.canonicalize().unwrap().to_string_lossy()));
return ();
}
let closest_files = TodoFile::get_closest_files(files.collect(), target, args.number);
if args.list {
closest_files
.into_iter()

View File

@@ -1,10 +1,7 @@
use chrono::naive::NaiveDate;
use regex::Regex;
use std::cmp::min;
use std::convert::TryFrom;
use std::fs::DirEntry;
use std::path::PathBuf;
use std::str::FromStr;
use crate::file::FileNameParseError;
@@ -14,56 +11,6 @@ pub struct File {
pub date: NaiveDate,
}
pub enum FileError {
//IOError(&'static str),
ParseError(&'static str),
}
impl File {
fn capture_as_number<T: FromStr>(capture: &regex::Captures, name: &str) -> Result<T, String> {
Ok(capture
.name(name)
.unwrap()
.as_str()
.parse::<T>()
.ok()
.ok_or("Something went wrong".to_owned())?)
}
fn get_file_regex() -> Regex {
//TODO This would ideally be configurable
Regex::new(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}).md")
.expect("could not create regex")
}
}
impl TryFrom<DirEntry> for File {
type Error = FileError;
fn try_from(direntry: DirEntry) -> Result<Self, Self::Error> {
let re = File::get_file_regex();
// println!("{:?}", re);
let file_name = direntry.file_name();
let file_name_str = match file_name.to_str() {
Some(name) => name,
_ => "",
};
// println!("{:?}", file_name_str);
if let Some(caps) = re.captures(file_name_str) {
let year: i32 = Self::capture_as_number(&caps, "year").unwrap();
let month: u32 = Self::capture_as_number(&caps, "month").unwrap();
let day: u32 = Self::capture_as_number(&caps, "day").unwrap();
return Ok(Self {
file: direntry.path(),
date: NaiveDate::from_ymd_opt(year, month, day).unwrap(),
});
};
Err(FileError::ParseError("Could not parse file name"))
}
}
fn try_get_date(file: &PathBuf) -> Result<NaiveDate, FileNameParseError> {
let file_name = file
.file_name()

View File

@@ -2,5 +2,4 @@ mod file;
mod tasks;
pub use file::File;
pub use tasks::{Status, TaskGroup};
pub use tasks::{Status, Task, TaskGroup};

View File

@@ -3,7 +3,7 @@ use std::borrow::Borrow;
use comrak::nodes::AstNode;
use comrak::nodes::NodeValue;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct TaskGroup {
pub name: String,
pub tasks: Vec<Task>,
@@ -11,7 +11,7 @@ pub struct TaskGroup {
}
// This does not support subtasks, need to figure out best path forward
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct Task {
pub status: Status,
pub text: String,
@@ -81,7 +81,7 @@ impl ToString for Task {
.map(|task| task.to_string())
.collect::<Vec<_>>()
.join("\n");
format!("\n{}", text).trim_end().replace("\n", "\n ")
format!("\n{}", text).trim_end().replace("\n", "\n ")
} else {
"".into()
};
@@ -92,6 +92,7 @@ impl ToString for Task {
impl<'a> TryFrom<&'a AstNode<'a>> for Task {
type Error = TaskError;
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 {
@@ -158,6 +159,7 @@ impl ToString for TaskGroup {
impl<'a> TryFrom<&'a AstNode<'a>> for TaskGroup {
type Error = TaskError;
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 {