From aaec1f1f78b802ce9895bc553d361474c5d94a3b Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 22 Apr 2024 21:25:29 +0200 Subject: [PATCH] jrnl: adding entries now works!! --- programs/jrnl/src/commands.rs | 3 +- programs/jrnl/src/commands/add_entry.rs | 68 ++++++++++++++++++++++ programs/jrnl/src/commands/list_entries.rs | 9 +-- programs/jrnl/src/main.rs | 16 +++-- programs/jrnl/src/md.rs | 6 +- 5 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 programs/jrnl/src/commands/add_entry.rs diff --git a/programs/jrnl/src/commands.rs b/programs/jrnl/src/commands.rs index 7340468..c294e5e 100644 --- a/programs/jrnl/src/commands.rs +++ b/programs/jrnl/src/commands.rs @@ -1,3 +1,2 @@ +pub mod add_entry; pub mod list_entries; - -mod add_entry {} diff --git a/programs/jrnl/src/commands/add_entry.rs b/programs/jrnl/src/commands/add_entry.rs new file mode 100644 index 0000000..8dd1b92 --- /dev/null +++ b/programs/jrnl/src/commands/add_entry.rs @@ -0,0 +1,68 @@ +use std::{ + env, + fs::{self, OpenOptions}, + io::{self, Write}, + path::PathBuf, + process::Command, +}; + +use temp_file::{TempFile, TempFileBuilder}; + +use crate::md::{Entry, ToMd}; + +// TODO: the usual (better error handling) +pub fn add_entry(path: PathBuf, title: Option) -> io::Result<()> { + if !path.exists() { + eprintln!("Journal file does not exist at {path:?}, exiting..."); + std::process::exit(1); + } + + let title = prompt("Title")?; + + let tmp = TempFileBuilder::new() + .suffix(".jrnl-entry.md") + .build() + .unwrap(); + + let editor = match env::var("EDITOR") { + Ok(val) => val, + Err(env::VarError::NotPresent) => { + eprintln!("EDITOR not set, exiting..."); + std::process::exit(1); + } + _ => unreachable!(), + }; + + let mut editor_cmd = Command::new(&editor); + editor_cmd.arg(tmp.path()); + editor_cmd.status().unwrap(); + + let content = fs::read_to_string(tmp.path()).unwrap(); + + let now = chrono::offset::Local::now(); + + let entry = Entry { + timestamp: now.fixed_offset(), + title: &title, + content: &content, + }; + + let mut file = OpenOptions::new() + .write(true) + .append(true) + .open(path) + .unwrap(); + + write!(file, "{}", entry.to_md())?; + + Ok(()) +} + +fn prompt(title: &str) -> io::Result { + print!("{}: ", title); + let _ = io::stdout().flush(); + let mut buf = String::new(); + let stdin = io::stdin(); + stdin.read_line(&mut buf)?; + Ok(buf) +} diff --git a/programs/jrnl/src/commands/list_entries.rs b/programs/jrnl/src/commands/list_entries.rs index 9471095..b1f617b 100644 --- a/programs/jrnl/src/commands/list_entries.rs +++ b/programs/jrnl/src/commands/list_entries.rs @@ -1,22 +1,23 @@ use owo_colors::OwoColorize; -use std::{fs, path::PathBuf}; +use std::{fs, io, path::PathBuf}; use crate::md::Doc; -pub fn list_entries(path: PathBuf) { - let file = fs::read_to_string(path).unwrap(); +pub fn list_entries(path: PathBuf) -> io::Result<()> { + let file = fs::read_to_string(path)?; if let Some(doc) = Doc::new(&file) { + let termsize::Size { cols, .. } = termsize::get().unwrap(); 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())); println!("{}{r}{padding}{}", n.cyan(), l.white()) } + Ok(()) } else { eprintln!("Parsing error..."); std::process::exit(1); diff --git a/programs/jrnl/src/main.rs b/programs/jrnl/src/main.rs index 22faae3..4084e83 100644 --- a/programs/jrnl/src/main.rs +++ b/programs/jrnl/src/main.rs @@ -1,8 +1,9 @@ #![feature(iter_collect_into)] use clap::{Parser, Subcommand}; -use std::{fs, path::PathBuf}; +use std::{fs, io, path::PathBuf}; use crate::{ + commands::add_entry::add_entry, commands::list_entries::list_entries, md::{Doc, ToMd}, }; @@ -23,23 +24,26 @@ struct Cli { enum Command { #[command(aliases = ["l", "ls", "list"])] ListEntries, - Add, + Add { + title: Option, + }, } -fn main() { +fn main() -> io::Result<()> { let cli = Cli::parse(); println!("Hello, world!"); println!("cli: {cli:#?}"); match cli.command { Some(Command::ListEntries) => list_entries(cli.s10e_jrnl_file_loc.clone()), - Some(Command::Add) => todo!(), + Some(Command::Add { title }) => add_entry(cli.s10e_jrnl_file_loc.clone(), title), None => { // TODO: handle btter - let file = fs::read_to_string(cli.s10e_jrnl_file_loc).unwrap(); + let file = fs::read_to_string(cli.s10e_jrnl_file_loc)?; let doc = Doc::new(&file).unwrap(); - println!("{}", doc.to_md()) + println!("{}", doc.to_md()); + Ok(()) } } } diff --git a/programs/jrnl/src/md.rs b/programs/jrnl/src/md.rs index cd3ab43..8453c77 100644 --- a/programs/jrnl/src/md.rs +++ b/programs/jrnl/src/md.rs @@ -58,7 +58,11 @@ impl ToMd for Entry<'_> { fn to_md(&self) -> String { format!( "## {}: {}\n\n{}\n\n", - self.timestamp, self.title, self.content + self.timestamp + .fixed_offset() + .to_rfc3339_opts(chrono::SecondsFormat::Secs, false), + self.title, + self.content ) } }