summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Sotoudeh <matthewsot@outlook.com>2022-01-23 21:32:41 -0800
committerMatthew Sotoudeh <matthewsot@outlook.com>2022-01-23 21:32:41 -0800
commit99286549bb6bd205a342bd98fc03223ec263ca45 (patch)
tree1041fe7b1b11a79ee9cd9e6e1a027c03308c9394
parentd4839fe311a49ac2484b12487b8da6f0ae203dca (diff)
'./wtd describe [week]' command works
-rw-r--r--src/dates.rs12
-rw-r--r--src/html_calendar.rs19
-rw-r--r--src/main.rs24
-rw-r--r--src/md_calendar.rs46
-rw-r--r--src/parse.rs5
-rw-r--r--src/task.rs1
6 files changed, 91 insertions, 16 deletions
diff --git a/src/dates.rs b/src/dates.rs
index c4c9c0d..09aac82 100644
--- a/src/dates.rs
+++ b/src/dates.rs
@@ -52,11 +52,21 @@ fn week_file(week_start: NaiveDate) -> Option<String> {
return path_if_exists(&filename);
}
+pub fn parse_week_str(week_str: &str) -> Option<NaiveDate> {
+ let mut cased = week_str.to_string();
+ let upper_start = cased.remove(0).to_uppercase().to_string();
+ cased.insert_str(0, &upper_start);
+ return match NaiveDate::parse_from_str(&cased, "%b_%d_%Y") {
+ Ok(d) => Some(d),
+ Err(_) => None,
+ }
+}
+
fn path_if_exists(name: &str) -> Option<String> {
return if Path::new(name).exists() { Some(name.to_string()) } else { None };
}
-fn week_start_of(date: &NaiveDate) -> NaiveDate {
+pub fn week_start_of(date: &NaiveDate) -> NaiveDate {
// number_from_monday() is 1-indexed, for some reason...
let days_from_monday = date.weekday().number_from_monday() - 1;
return *date - Duration::days(days_from_monday.into());
diff --git a/src/html_calendar.rs b/src/html_calendar.rs
index 2902caa..c050f77 100644
--- a/src/html_calendar.rs
+++ b/src/html_calendar.rs
@@ -2,7 +2,7 @@ use std::io::prelude::*;
use std::fs::File;
use std::collections::HashMap;
use std::path::Path;
-use chrono::{NaiveTime, Duration, Local};
+use chrono::{NaiveTime, Duration, NaiveDate};
use crate::task::*;
pub enum CalendarPrivacy {
@@ -10,14 +10,14 @@ pub enum CalendarPrivacy {
Private,
}
-pub fn tasks_to_html_file(tasks: &Vec<Task>, privacy: CalendarPrivacy, file_name: &str) {
- let html = tasks_to_html(tasks, privacy);
+pub fn tasks_to_html_file(tasks: &Vec<Task>, first_date: NaiveDate, last_date: NaiveDate, privacy: CalendarPrivacy, file_name: &str) {
+ let html = tasks_to_html(tasks, first_date, last_date, 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 {
+fn tasks_to_html(tasks: &Vec<Task>, first_date: NaiveDate, last_date: NaiveDate, 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."),
@@ -28,12 +28,11 @@ fn tasks_to_html(tasks: &Vec<Task>, privacy: CalendarPrivacy) -> String {
let mut html = "<html><head><meta charset=\"UTF-8\"><title>Calendar</title><link rel=\"stylesheet\" href=\"calendar_style.css\"></link></head><body>".to_string();
- let n_days = 14;
- let start_period = Local::now().date().naive_local();
- let end_period = start_period + Duration::days(n_days);
+ let n_days = (last_date - first_date).num_days() + 1;
+
let mut week_task_ids: Vec<usize> = Vec::new();
for (i, task) in tasks.iter().enumerate() {
- if task.date >= start_period && task.date < end_period {
+ if first_date <= task.date && task.date <= last_date {
week_task_ids.push(i);
}
}
@@ -52,7 +51,7 @@ fn tasks_to_html(tasks: &Vec<Task>, privacy: CalendarPrivacy) -> String {
html.push_str("<tr><th>Time</th>");
for offset in 0..n_days {
html.push_str("<th>");
- html.push_str(&(start_period + Duration::days(offset)).format("%a %-m/%-d/%y").to_string());
+ html.push_str(&(first_date + Duration::days(offset)).format("%a %-m/%-d/%y").to_string());
html.push_str("</th>");
}
html.push_str("</tr>");
@@ -64,7 +63,7 @@ fn tasks_to_html(tasks: &Vec<Task>, privacy: CalendarPrivacy) -> String {
let timespan_end = NaiveTime::from_hms(0, 0, 0) + Duration::minutes((i + 1) * min_incr);
for offset in 0..n_days {
// (1) Find all task ids that intersect this timespan on this day.
- let this_date = start_period + Duration::days(offset);
+ let this_date = first_date + Duration::days(offset);
let on_this_date: Vec<usize>
= week_task_ids.iter().map(|&idx| idx)
.filter(|&idx| tasks[idx].date == this_date).collect();
diff --git a/src/main.rs b/src/main.rs
index 49c8152..59a7a0d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
use std::env;
-use chrono::{Local, Duration};
+use chrono::{Local, Duration, Datelike};
mod task;
use task::*;
@@ -7,6 +7,8 @@ mod parse;
use parse::*;
mod html_calendar;
use html_calendar::*;
+mod md_calendar;
+use md_calendar::*;
mod dates;
use dates::*;
@@ -25,12 +27,26 @@ fn command_html() {
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");
+ tasks_to_html_file(&tasks, first_date, last_date, CalendarPrivacy::Public, &"public.html");
+ tasks_to_html_file(&tasks, first_date, last_date, CalendarPrivacy::Private, &"private.html");
}
fn command_describe(week: &str) {
- // TODO
+ let first_date
+ = parse_week_str(week).expect("Invalid week string provided. Should be, e.g., jan_24_2022");
+ if first_date.weekday().number_from_monday() != 1 { // 1-based, for some reason.
+ panic!("The provided week should start on a Monday.");
+ }
+ let last_date = first_date + Duration::days(6); // 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));
+ }
+
+ let md = tasks_to_md(&tasks, first_date, last_date);
+ println!("{}", md);
}
fn command_generate(week: &str) {
diff --git a/src/md_calendar.rs b/src/md_calendar.rs
new file mode 100644
index 0000000..d010628
--- /dev/null
+++ b/src/md_calendar.rs
@@ -0,0 +1,46 @@
+use chrono::{Duration, NaiveDate};
+use crate::task::*;
+use crate::dates::*;
+
+pub fn tasks_to_md(tasks: &Vec<Task>, first_date: NaiveDate, last_date: NaiveDate) -> String {
+ let first_week = week_start_of(&first_date);
+ let last_week = week_start_of(&last_date); // inclusive
+
+ let mut md_out = "".to_string();
+
+ let mut curr_week = first_week;
+ while curr_week <= last_week {
+ let curr_week_last_date = curr_week + Duration::days(6);
+
+ // Collect all the relevant tasks.
+ let mut week_task_ids: Vec<usize> = Vec::new();
+ for (i, task) in tasks.iter().enumerate() {
+ if curr_week <= task.date && task.date <= curr_week_last_date
+ && first_date <= task.date && task.date <= last_date {
+ week_task_ids.push(i);
+ }
+ }
+ week_task_ids.sort_by(|a, b| cmp_tasks(&tasks[*a], &tasks[*b]));
+
+ // Print the week.
+ if week_task_ids.len() > 0 {
+ md_out.push_str(&format!("# {}\n", curr_week.format("%-m/%-d/%y").to_string()));
+ let mut last_written_date = curr_week - Duration::days(1);
+ for task_id in week_task_ids {
+ let task = &tasks[task_id];
+ if last_written_date != task.date {
+ if last_written_date != curr_week - Duration::days(1) { // TODO: something smarter
+ md_out.push('\n');
+ }
+ md_out.push_str(&format!("## {}\n", task.date.format("%A").to_string()));
+ last_written_date = task.date;
+ }
+ md_out.push_str(&task.raw);
+ }
+ }
+
+ // Next iter.
+ curr_week = curr_week + Duration::days(7);
+ }
+ return md_out;
+}
diff --git a/src/parse.rs b/src/parse.rs
index d751579..876b861 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -6,7 +6,6 @@ use chrono::{Datelike, NaiveDate, NaiveTime, Weekday, Duration, Timelike};
use crate::task::*;
use crate::dates::*;
-use crate::html_calendar::*;
// 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> {
@@ -58,12 +57,16 @@ fn parse_file_str(file_str: &str, implicit_week: Option<NaiveDate>) -> Vec<Task>
start_time: None,
end_time: None,
details: "".to_string(),
+ raw: l.to_string(),
tags: Vec::new(),
});
+ tasks.last_mut().expect("").raw.push('\n');
let details = l.get(5..).expect("").trim();
handle_task_details(details, tasks.last_mut().expect("Unexpected error..."));
} else if l.starts_with(" ") {
// Extends the last task.
+ tasks.last_mut().expect("").raw.push_str(l);
+ tasks.last_mut().expect("").raw.push('\n');
handle_task_details(l, tasks.last_mut().expect("Unexpected error..."));
} else if l.trim().len() > 0 {
eprint!("Ignoring line: {}\n", l);
diff --git a/src/task.rs b/src/task.rs
index 871d8ff..952a35e 100644
--- a/src/task.rs
+++ b/src/task.rs
@@ -6,6 +6,7 @@ pub struct Task {
pub start_time: Option<NaiveTime>,
pub end_time: Option<NaiveTime>,
pub details: String,
+ pub raw: String,
pub tags: Vec<String>,
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback