jrnl: adding entries now works!!
This commit is contained in:
parent
b967f6e90e
commit
aaec1f1f78
5 changed files with 89 additions and 13 deletions
|
@ -1,3 +1,2 @@
|
||||||
|
pub mod add_entry;
|
||||||
pub mod list_entries;
|
pub mod list_entries;
|
||||||
|
|
||||||
mod add_entry {}
|
|
||||||
|
|
68
programs/jrnl/src/commands/add_entry.rs
Normal file
68
programs/jrnl/src/commands/add_entry.rs
Normal file
|
@ -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<String>) -> 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<String> {
|
||||||
|
print!("{}: ", title);
|
||||||
|
let _ = io::stdout().flush();
|
||||||
|
let mut buf = String::new();
|
||||||
|
let stdin = io::stdin();
|
||||||
|
stdin.read_line(&mut buf)?;
|
||||||
|
Ok(buf)
|
||||||
|
}
|
|
@ -1,22 +1,23 @@
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, io, path::PathBuf};
|
||||||
|
|
||||||
use crate::md::Doc;
|
use crate::md::Doc;
|
||||||
|
|
||||||
pub fn list_entries(path: PathBuf) {
|
pub fn list_entries(path: PathBuf) -> io::Result<()> {
|
||||||
let file = fs::read_to_string(path).unwrap();
|
let file = fs::read_to_string(path)?;
|
||||||
|
|
||||||
if let Some(doc) = Doc::new(&file) {
|
if let Some(doc) = Doc::new(&file) {
|
||||||
|
let termsize::Size { cols, .. } = termsize::get().unwrap();
|
||||||
for (i, entry) in doc.entries.into_iter().enumerate() {
|
for (i, entry) in doc.entries.into_iter().enumerate() {
|
||||||
let n = format!("{:>2}", i + 1);
|
let n = format!("{:>2}", i + 1);
|
||||||
let r = format!(". {}", entry.title,);
|
let r = format!(". {}", entry.title,);
|
||||||
let l = format!(" {} ", crate::utils::format_datetime(entry.timestamp));
|
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())
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Parsing error...");
|
eprintln!("Parsing error...");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#![feature(iter_collect_into)]
|
#![feature(iter_collect_into)]
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, io, path::PathBuf};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
commands::add_entry::add_entry,
|
||||||
commands::list_entries::list_entries,
|
commands::list_entries::list_entries,
|
||||||
md::{Doc, ToMd},
|
md::{Doc, ToMd},
|
||||||
};
|
};
|
||||||
|
@ -23,23 +24,26 @@ struct Cli {
|
||||||
enum Command {
|
enum Command {
|
||||||
#[command(aliases = ["l", "ls", "list"])]
|
#[command(aliases = ["l", "ls", "list"])]
|
||||||
ListEntries,
|
ListEntries,
|
||||||
Add,
|
Add {
|
||||||
|
title: Option<String>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> io::Result<()> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
println!("cli: {cli:#?}");
|
println!("cli: {cli:#?}");
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Some(Command::ListEntries) => list_entries(cli.s10e_jrnl_file_loc.clone()),
|
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 => {
|
None => {
|
||||||
// TODO: handle btter
|
// 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();
|
let doc = Doc::new(&file).unwrap();
|
||||||
println!("{}", doc.to_md())
|
println!("{}", doc.to_md());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,11 @@ impl ToMd for Entry<'_> {
|
||||||
fn to_md(&self) -> String {
|
fn to_md(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"## {}: {}\n\n{}\n\n",
|
"## {}: {}\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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue