summaryrefslogtreecommitdiff
path: root/src/dates.rs
blob: 069af3f3c12a4bbd49c4545255dc018a88d22eb7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::fs;
use std::path::Path;
use std::collections::HashSet;
use crate::tasks_from_path;
// use chrono::{Datelike, NaiveDate, NaiveTime, Weekday, Duration, Timelike};
use chrono::{Datelike, NaiveDate, Duration};

pub struct WTDPath {
    pub path: String,
    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> {
    let mut paths: Vec<WTDPath> = vec![];
    if let Some(path) = path_if_exists("wtd.md") {
        paths.push(WTDPath {
            path: path,
            week_start: None,
            is_weekly_file: false,
        });
    }

    let weekly = path_if_exists("weekly.md");

    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(p), _] => p,
            [_, Some(p)] => p,
            [None, None] => {
                curr_week = curr_week + Duration::weeks(1);
                continue
            },
        };
        paths.push(WTDPath {
            path: path.to_string(),
            week_start: Some(curr_week),
            is_weekly_file: maybe_week_path.is_none(),
        });
        curr_week = curr_week + Duration::weeks(1);
    }

    return paths;
}

/* This is a pretty rough way of doing it, but it should work. Basically:
 * - Pull the tasks from wtd.md, record a set of the weeks involved.
 * - Also pull all tasks from any (future) [week].md files, _removing_ those weeks from the set.
 * - For every remaining week mentioned in wtd.md but not a [week].md, add a copy of weekly.md for
 *   that week.
 * - Finally, if there were no future [week].mds, add a copy of weekly.md for a date far in the
 *   future (i.e., not to conflict with any other dates).
 */
pub fn relevant_files_starting<'a>(start: &'a NaiveDate) -> Vec<WTDPath> {
    let start_week = week_start_of(start);
    let mut paths: Vec<WTDPath> = vec![];
    let mut weeks = HashSet::new();
    let mut oldest_date: NaiveDate = *start;
    if let Some(path) = path_if_exists("wtd.md") {
        paths.push(WTDPath {
            path: path,
            week_start: None,
            is_weekly_file: false,
        });
        for task in tasks_from_path(paths.last().unwrap()) {
            if task.date < *start {
                continue;
            }
            if task.date > oldest_date {
                oldest_date = task.date;
            }
            let week = week_start_of(&task.date);
            weeks.insert(week);
        }
    }

    // https://stackoverflow.com/questions/26076005
    for path in fs::read_dir("./").unwrap() {
        let mut file_name = path.unwrap().path().to_str().unwrap().to_string();
        file_name.remove(0);
        file_name.remove(0); // removes the ./
        if let Some(week) = maybe_valid_week_file(&file_name) {
            if week < start_week {
                continue;
            }
            if week + Duration::days(6) > oldest_date {
                oldest_date = week + Duration::days(6);
            }
            paths.push(WTDPath {
                path: path_if_exists(&file_name).unwrap(),
                week_start: Some(week),
                is_weekly_file: false,
            });
            weeks.remove(&week);
        }
    }

    let weekly = path_if_exists("weekly.md");
    if weekly.is_some() {
        for week in &weeks {
            paths.push(WTDPath {
                path: weekly.as_ref().unwrap().to_string(),
                week_start: Some(*week),
                is_weekly_file: true,
            });
        }
        if weeks.len() == 0 {
            paths.push(WTDPath {
                path: weekly.as_ref().unwrap().to_string(),
                week_start: Some(week_start_of(&(oldest_date + Duration::days(7)))),
                is_weekly_file: true,
            });
        }
    }

    return paths;
}

fn week_file(week_start: NaiveDate) -> Option<String> {
    let filename = week_start.format("%b_%d_%Y.md").to_string().to_lowercase();
    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,
    }
}

pub fn maybe_valid_week_file(week_file_name: &str) -> Option<NaiveDate> {
    match week_file_name.rsplit_once(".") {
        Some((name, "md")) => {
            if let Some(date) = parse_week_str(name) {
                return if week_start_of(&date) == date { Some(date) } else { None };
            }
            return None;
        },
        _ => return None,
    }
}

fn path_if_exists(name: &str) -> Option<String> {
    return if Path::new(name).exists() { Some(name.to_string()) } else { None };
}

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());
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback