67 lines
1.7 KiB
Rust
67 lines
1.7 KiB
Rust
use chrono::{DateTime, FixedOffset};
|
|
use std::convert::identity;
|
|
|
|
pub trait ToMd {
|
|
fn to_md(&self) -> String;
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Doc<'src> {
|
|
pub entries: Vec<Entry<'src>>,
|
|
}
|
|
|
|
impl<'src> Doc<'src> {
|
|
// TODO: better parsing errors?
|
|
pub fn new(f: &'src str) -> Option<Self> {
|
|
let entries = f
|
|
.split("\n## ")
|
|
.map(|s| s.split_once("\n"))
|
|
.skip(1)
|
|
.filter_map(identity)
|
|
.map(|(title, content)| (title.split_once(": "), content))
|
|
.map(|(title, content)| {
|
|
if let Some((ts, title)) = title {
|
|
Some(Entry {
|
|
timestamp: DateTime::parse_from_rfc3339(ts).unwrap(),
|
|
title,
|
|
content: content.trim_matches('\n'),
|
|
})
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
entries.iter().all(|it| it.is_some()).then_some(Self {
|
|
entries: entries.into_iter().filter_map(identity).collect(),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ToMd for Doc<'_> {
|
|
fn to_md(&self) -> String {
|
|
let mut r = "# Journal\n\n".to_owned();
|
|
|
|
self.entries.iter().fold(r, |mut r, it| r + &it.to_md())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Entry<'src> {
|
|
pub timestamp: DateTime<FixedOffset>,
|
|
pub title: &'src str,
|
|
pub content: &'src str,
|
|
}
|
|
|
|
impl ToMd for Entry<'_> {
|
|
fn to_md(&self) -> String {
|
|
format!(
|
|
"## {}: {}\n\n{}\n\n",
|
|
self.timestamp
|
|
.fixed_offset()
|
|
.to_rfc3339_opts(chrono::SecondsFormat::Secs, false),
|
|
self.title,
|
|
self.content
|
|
)
|
|
}
|
|
}
|