From 1aee78643c2365e9aa36bb13c2a716feb721a120 Mon Sep 17 00:00:00 2001 From: alemidev Date: Sun, 13 Mar 2022 20:13:13 +0100 Subject: [PATCH] first commit --- Cargo.toml | 11 +++++ src/main.rs | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..391a7e5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "memo-cli" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +argparse = "0.2.2" +chrono = "0.4.19" +rusqlite = { version="0.27.0", features=["chrono"] } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..eb36fa6 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,129 @@ +extern crate argparse; + +use argparse::{ArgumentParser, Store, StoreTrue}; +use chrono::{DateTime, Duration, Utc}; +use rusqlite::{params, Connection, Error}; + +struct Memo { + id: u32, + body: String, + due: DateTime, +} + +fn init_db(path: &str) -> Result { + let connection = Connection::open(path)?; + + connection.execute( + "CREATE TABLE IF NOT EXISTS memo ( + id INTEGER PRIMARY KEY, + body TEXT NOT NULL, + due DATETIME + );", + [], + )?; + + return Ok(connection); +} + +fn all(conn: Connection) -> Result, rusqlite::Error> { + let mut statement = conn.prepare("SELECT * FROM memo ORDER BY due, id")?; + let mut rows = statement.query([])?; + + let mut results = Vec::new(); + + while let Some(row) = rows.next()? { + results.push(Memo { + id: row.get(0)?, + body: row.get(1)?, + due: row.get(2)?, + }); + } + + return Ok(results); +} + +pub trait PrettyPrint { + fn pretty(&self) -> String; +} + +impl PrettyPrint for Duration { + fn pretty(&self) -> String { + if self.num_days().abs() > 400 { + return format!("{}y {}m", self.num_days().abs() / 365, (self.num_days() % (30*12)) / 30); + } else if self.num_days().abs() >= 365 { + return format!("{}y", self.num_days().abs() / 365); + } else if self.num_days().abs() >= 90 { + return format!("{}m", self.num_days().abs() / 30); // sort of + } else if self.num_days().abs() >= 1 { + return format!("{}d", self.num_days().abs()); + } else if self.num_hours().abs() > 0 { + let h = self.num_minutes().abs() / 60; + let m = self.num_minutes().abs() % 60; + return format!("{}h {}min", h, m); + } else if self.num_minutes().abs() > 0 { + return format!("{}min", self.num_minutes().abs()); + } else if self.num_seconds().abs() > 0 { + return format!("{}s", self.num_seconds().abs()); + } + return self.to_string(); + } +} + +fn main() { + let home_path = std::env!("HOME").to_string(); + if home_path.len() < 1 { + panic!("Cannot work without a home folder"); + } + + let mut version = false; + let mut memo: String = "".to_string(); + let mut db_path: String = home_path + "/.local/share/memo-cli.db"; + + { + // this block limits scope of borrows by ap.refer() method + let mut ap = ArgumentParser::new(); + ap.set_description("A simple tool to remember things"); + ap.refer(&mut version).add_option( + &["-V", "--version"], + StoreTrue, + "Show current version and die", + ); + ap.refer(&mut memo) + .add_option(&["-n", "--new"], Store, "Add a new memo"); + ap.refer(&mut db_path) + .add_option(&["--path"], Store, "Specify db path"); + + ap.parse_args_or_exit(); + } + + if version { + const VERSION: &str = env!("CARGO_PKG_VERSION"); + println!("memo-cli v{}", VERSION); + return; + } + + let connection = + init_db(&db_path).unwrap_or_else(|err| panic!("Could not open db : {}", err.to_string())); + + if memo.len() > 0 { + connection + .execute( + "INSERT INTO memo (body, due) VALUES (?, ?)", + params![memo, Utc::now()], + ) + .unwrap_or_else(|err| panic!("Could not insert into db : {}", err.to_string())); + println!("New memo : '{}'", memo); + } else { + let zero_duration = Duration::seconds(0); + let memos = all(connection) + .unwrap_or_else(|err| panic!("Could not read all memos : {}", err.to_string())); + for m in memos { + let delta = m.due - Utc::now(); + if delta.le(&zero_duration) { + println!("[*] {} : +{} \t[{}]", m.body, delta.pretty(), m.id); + } else { + println!(" * {} : -{} \t[{}]", m.body, delta.pretty(), m.id); + } + } + } +}