diff --git a/Cargo.lock b/Cargo.lock index 9415901..752d275 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,6 +412,7 @@ dependencies = [ "owo-colors", "petgraph", "ratatui", + "temp-file", "termsize", ] @@ -799,6 +800,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "temp-file" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f210bda61d003f311d95611d1b68361df8fe8e732c3609f945441bde881321d" + [[package]] name = "termion" version = "1.5.6" diff --git a/programs/jrnl/Cargo.toml b/programs/jrnl/Cargo.toml index 0b97fee..12f231a 100644 --- a/programs/jrnl/Cargo.toml +++ b/programs/jrnl/Cargo.toml @@ -13,4 +13,5 @@ markdown = "0.3.0" owo-colors = "4.0.0" petgraph = "0.6.4" ratatui = "0.26.2" +temp-file = "0.1.8" termsize = "0.1.6" diff --git a/programs/jrnl/src/commands/list_entries.rs b/programs/jrnl/src/commands/list_entries.rs index 6d46388..9471095 100644 --- a/programs/jrnl/src/commands/list_entries.rs +++ b/programs/jrnl/src/commands/list_entries.rs @@ -5,16 +5,20 @@ use crate::md::Doc; pub fn list_entries(path: PathBuf) { let file = fs::read_to_string(path).unwrap(); - let doc = Doc::new(&file); - for (i, entry) in doc.entries.into_iter().enumerate() { - let n = format!("{:>2}", i + 1); - let r = format!(". {}", entry.title,); - let l = format!(" {} ", crate::utils::format_datetime(entry.timestamp)); - let termsize::Size { cols, .. } = termsize::get().unwrap(); + if let Some(doc) = Doc::new(&file) { + for (i, entry) in doc.entries.into_iter().enumerate() { + let n = format!("{:>2}", i + 1); + let r = format!(". {}", entry.title,); + let l = format!(" {} ", crate::utils::format_datetime(entry.timestamp)); + let termsize::Size { cols, .. } = termsize::get().unwrap(); - let padding = " ".repeat(cols as usize - (n.len() + r.len() + l.len())); + let padding = " ".repeat(cols as usize - (n.len() + r.len() + l.len())); - println!("{}{r}{padding}{}", n.cyan(), l.white()) + println!("{}{r}{padding}{}", n.cyan(), l.white()) + } + } else { + eprintln!("Parsing error..."); + std::process::exit(1); } } diff --git a/programs/jrnl/src/main.rs b/programs/jrnl/src/main.rs index 294ade8..b9ba013 100644 --- a/programs/jrnl/src/main.rs +++ b/programs/jrnl/src/main.rs @@ -1,3 +1,4 @@ +#![feature(iter_collect_into)] use clap::{Parser, Subcommand}; use std::{fs, path::PathBuf}; @@ -34,8 +35,7 @@ fn main() { // TODO: handle btter let file = fs::read_to_string(cli.s10e_jrnl_file_loc).unwrap(); - let doc = Doc::new(&file); - dbg!(doc); + let doc = dbg!(Doc::new(&file)); } } } diff --git a/programs/jrnl/src/md.rs b/programs/jrnl/src/md.rs index b04ef2e..80ba946 100644 --- a/programs/jrnl/src/md.rs +++ b/programs/jrnl/src/md.rs @@ -1,59 +1,43 @@ use chrono::{DateTime, FixedOffset}; use markdown::{Block, Span}; +use std::convert::identity; #[derive(Debug)] -pub struct Doc { - pub title: Vec, - pub entries: Vec, +pub struct Doc<'src> { + pub entries: Vec>, } -impl Doc { - pub fn new(f: &str) -> Self { - let mut entries = Vec::new(); - let mut doc_title = vec![Span::Text("Journal".to_owned())]; - let toks = markdown::tokenize(f); - let mut current = None; - - for tok in toks { - match tok { - Block::Header(title, 1) => doc_title = title, - Block::Header(entry_title, 2) => { - if let Some(cur) = current.take() { - entries.push(cur); - } - - let Some(Span::Text(title)) = entry_title.first() else { - eprintln!("Error: Titles should be text."); - std::process::exit(1); - }; - - let (ts, entry_title) = title.split_once(": ").unwrap(); - let ts = DateTime::parse_from_rfc3339(ts).unwrap(); - // let ts = PrimitiveDateTime::parse(ts, &DT_FORMAT).unwrap(); - - current = Some(Entry { - timestamp: ts, - title: entry_title.to_owned(), - content: Vec::new(), - }); +impl<'src> Doc<'src> { + // TODO: better parsing errors? + pub fn new(f: &'src str) -> Option { + 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 } - other => current.as_mut().unwrap().content.push(other), - } - } - if let Some(cur) = current { - entries.push(cur); - } + }) + .collect::>(); - Self { - title: doc_title, - entries, - } + entries.iter().all(|it| it.is_some()).then_some(Self { + entries: entries.into_iter().filter_map(identity).collect(), + }) } } -#[derive(Debug)] -pub struct Entry { +#[derive(Debug, Clone)] +pub struct Entry<'src> { pub timestamp: DateTime, - pub title: String, - pub content: Vec, + pub title: &'src str, + pub content: &'src str, }