mirror of
https://git.alemi.dev/memo-cli.git
synced 2024-11-22 08:54:49 +01:00
first commit
This commit is contained in:
parent
7fde73888f
commit
1aee78643c
2 changed files with 140 additions and 0 deletions
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
|
@ -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"] }
|
129
src/main.rs
Normal file
129
src/main.rs
Normal file
|
@ -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<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_db(path: &str) -> Result<Connection, Error> {
|
||||||
|
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<Vec<Memo>, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue