summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Sotoudeh <matthewsot@outlook.com>2022-01-23 20:00:30 -0800
committerMatthew Sotoudeh <matthewsot@outlook.com>2022-01-23 20:00:30 -0800
commitf12dfa1375cc9bf88f4e8defc400b462e9d895aa (patch)
tree1c7d0da76d8db4513c87bbf0d66fac129970add3
parent3672ea38b85b077986351fd35574442aec81f579 (diff)
Locate which files to be read for advanced mode support
-rw-r--r--README.md2
-rw-r--r--src/dates.rs60
-rw-r--r--src/html_calendar.rs12
-rw-r--r--src/main.rs71
-rw-r--r--src/parse.rs28
5 files changed, 143 insertions, 30 deletions
diff --git a/README.md b/README.md
index 3f8ba1b..942577b 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ these `public_tags`, see `calendar_style.css`.
To generate the HTML calendars, run:
```
-$ cargo run
+$ cargo run html
```
You should now see `public.html` and `private.html` in the current directory.
diff --git a/src/dates.rs b/src/dates.rs
new file mode 100644
index 0000000..fc3863c
--- /dev/null
+++ b/src/dates.rs
@@ -0,0 +1,60 @@
+use std::path::Path;
+// use std::str::FromStr;
+// use chrono::{Datelike, NaiveDate, NaiveTime, Weekday, Duration, Timelike};
+use chrono::{Datelike, NaiveDate, Duration};
+
+pub struct WTDPath<'a> {
+ pub path: &'a Path,
+ pub week_start: Option<NaiveDate>,
+ pub is_weekly_file: bool,
+}
+
+// both start, end are inclusive.
+pub fn relevant_files<'a>(start: &'a NaiveDate, end: &'a NaiveDate) -> Vec<WTDPath<'a>> {
+ let mut paths: Vec<WTDPath> = vec![];
+ if let Some(path) = maybe_path("wtd.md".to_string()) {
+ paths.push(WTDPath {
+ path: &path,
+ week_start: None,
+ is_weekly_file: false,
+ });
+ }
+
+ let weekly = maybe_path("weekly.md".to_string());
+
+ let start_week = week_start_of(start);
+ let end_week = week_start_of(end); // inclusive
+
+ let mut curr_week = start_week;
+ while curr_week <= end_week {
+ let maybe_week_path = week_file(curr_week);
+ let path = match [maybe_week_path, weekly] {
+ [Some(path), _] => path,
+ [_, Some(path)] => path,
+ [None, None] => continue,
+ };
+ paths.push(WTDPath {
+ path: path,
+ week_start: Some(curr_week),
+ is_weekly_file: maybe_week_path.is_none(),
+ });
+ curr_week = curr_week + Duration::weeks(1);
+ }
+
+ return paths;
+}
+
+fn week_file(week_start: NaiveDate) -> Option<&'static Path> {
+ let filename = week_start.format("%b_%d_%Y.md").to_string().to_lowercase();
+ return maybe_path(filename);
+}
+
+fn maybe_path(name: String) -> Option<&'static Path> {
+ let path = Path::new("wtd.md");
+ return if path.exists() { Some(&path) } else { None };
+}
+
+fn week_start_of(date: &NaiveDate) -> NaiveDate {
+ let days_from_monday = date.weekday().number_from_monday();
+ return *date - Duration::days(days_from_monday.into());
+}
diff --git a/src/html_calendar.rs b/src/html_calendar.rs
index b16b987..2902caa 100644
--- a/src/html_calendar.rs
+++ b/src/html_calendar.rs
@@ -1,4 +1,7 @@
+use std::io::prelude::*;
+use std::fs::File;
use std::collections::HashMap;
+use std::path::Path;
use chrono::{NaiveTime, Duration, Local};
use crate::task::*;
@@ -7,7 +10,14 @@ pub enum CalendarPrivacy {
Private,
}
-pub fn tasks_to_html(tasks: &Vec<Task>, privacy: CalendarPrivacy) -> String {
+pub fn tasks_to_html_file(tasks: &Vec<Task>, privacy: CalendarPrivacy, file_name: &str) {
+ let html = tasks_to_html(tasks, privacy);
+ // https://riptutorial.com/rust/example/4276/write-in-a-file
+ let mut file = File::create(Path::new(file_name)).unwrap();
+ writeln!(&mut file, "{}", html).unwrap();
+}
+
+fn tasks_to_html(tasks: &Vec<Task>, privacy: CalendarPrivacy) -> String {
let public_tags = HashMap::from([
("busy", "I will be genuinely busy, e.g., a meeting with others."),
("rough", "The nature of the event (e.g., a hike) makes it difficult to preduct the exact start/end times."),
diff --git a/src/main.rs b/src/main.rs
index 6dfb441..49c8152 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,37 +1,56 @@
-use std::fs::File;
-use std::io::prelude::*;
-use std::path::Path;
+use std::env;
+use chrono::{Local, Duration};
mod task;
+use task::*;
mod parse;
use parse::*;
mod html_calendar;
use html_calendar::*;
+mod dates;
+use dates::*;
-// https://doc.rust-lang.org/std/fs/struct.File.html
-fn main() {
- let path = Path::new("wtd.md");
- let display = path.display();
+fn command_html() {
+ /* Pull tasks from:
+ * - wtd.md (always, assuming exists)
+ * - [week].md (assuming exists)
+ * - weekly.md (only included for weeks without a week.md)
+ */
+ let n_days = 14;
+ let first_date = Local::now().date().naive_local();
+ let last_date = first_date + Duration::days(n_days - 1); // inclusive
+ let paths = relevant_files(&first_date, &last_date);
+ let mut tasks: Vec<Task> = vec![];
+ for path in paths {
+ tasks.append(&mut tasks_from_path(&path));
+ }
+
+ tasks_to_html_file(&tasks, CalendarPrivacy::Public, &"public.html");
+ tasks_to_html_file(&tasks, CalendarPrivacy::Private, &"private.html");
+}
+
+fn command_describe(week: &str) {
+ // TODO
+}
+
+fn command_generate(week: &str) {
+ // TODO
+}
- // Open the path in read-only mode, returns `io::Result<File>`
- let mut file = match File::open(&path) {
- Err(why) => panic!("Error opening {}: {}", display, why),
- Ok(file) => file,
- };
+fn command_validate() {
+ // TODO
+}
- // Read the file contents into a string, returns `io::Result<usize>`
- let mut s = String::new();
- match file.read_to_string(&mut s) {
- Err(why) => panic!("Couldn't read {}: {}", display, why),
- Ok(_) => {
- let tasks = parse_file_str(&s);
- let public_html = tasks_to_html(&tasks, CalendarPrivacy::Public);
- let private_html = tasks_to_html(&tasks, CalendarPrivacy::Private);
- // https://riptutorial.com/rust/example/4276/write-in-a-file
- let mut public = File::create(Path::new("public.html")).unwrap();
- writeln!(&mut public, "{}", public_html).unwrap();
- let mut private = File::create(Path::new("private.html")).unwrap();
- writeln!(&mut private, "{}", private_html).unwrap();
- }
+// https://doc.rust-lang.org/std/fs/struct.File.html
+// https://doc.rust-lang.org/book/ch12-01-accepting-command-line-arguments.html
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ let str_args: Vec<&str> = args.iter().map(String::as_str).collect();
+ match str_args[..] {
+ [_, "html"] => command_html(),
+ [_, "describe", week] => command_describe(&week),
+ [_, "generate", week] => command_generate(&week),
+ [_, "validate"] => command_validate(),
+ _ => panic!("Invalid command. Valid commands are: html, describe [week], generate [week], and validate.")
}
}
diff --git a/src/parse.rs b/src/parse.rs
index 079e83a..a896cc2 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -1,10 +1,34 @@
+use std::fs::File;
+use std::io::prelude::*;
use std::str::FromStr;
use chrono::{Datelike, NaiveDate, NaiveTime, Weekday, Duration, Timelike};
-// mod task;
use crate::task::*;
+use crate::dates::*;
+use crate::html_calendar::*;
-pub fn parse_file_str(file_str: &str) -> Vec<Task> {
+// Translates a Path into a vector of tasks. Panics if the path cannot be opened or read from.
+pub fn tasks_from_path(wtd_path: &WTDPath) -> Vec<Task> {
+ let path = wtd_path.path;
+ let display = path.display();
+
+ // Open the path in read-only mode, returns `io::Result<File>`
+ let mut file = match File::open(&path) {
+ Err(why) => panic!("Error opening {}: {}", display, why),
+ Ok(file) => file,
+ };
+
+ // Read the file contents into a string, returns `io::Result<usize>`
+ let mut s = String::new();
+ match file.read_to_string(&mut s) {
+ Err(why) => panic!("Couldn't read {}: {}", display, why),
+ Ok(_) => {
+ return parse_file_str(&s);
+ }
+ }
+}
+
+fn parse_file_str(file_str: &str) -> Vec<Task> {
let mut tasks = Vec::new();
let mut start_date = None;
let mut the_date = None;
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback