mirror of
https://git.alemi.dev/memo-cli.git
synced 2024-11-25 03:14:48 +01:00
add basic command to edit memos
This commit is contained in:
parent
581aca2fb1
commit
5d4c206b25
3 changed files with 68 additions and 9 deletions
44
src/main.rs
44
src/main.rs
|
@ -1,13 +1,14 @@
|
||||||
mod storage;
|
mod storage;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use chrono::{DateTime, Utc, Local};
|
use chrono::{DateTime, Local, Utc};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
use colored::Colorize;
|
||||||
|
use const_format::concatcp;
|
||||||
|
use git_version::git_version;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use storage::{open_sqlite_storage, Memo, MemoStorage};
|
use storage::{open_sqlite_storage, Memo, MemoStorage};
|
||||||
use utils::{parse_human_duration, HumanDisplay};
|
use utils::{find_by_regex, parse_human_duration, HumanDisplay};
|
||||||
use git_version::git_version;
|
|
||||||
use const_format::concatcp;
|
|
||||||
|
|
||||||
const GIT_VERSION: &str = git_version!();
|
const GIT_VERSION: &str = git_version!();
|
||||||
const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
@ -47,7 +48,15 @@ enum Commands {
|
||||||
search: String,
|
search: String,
|
||||||
#[clap(long, help = "delete more than one task if matched")]
|
#[clap(long, help = "delete more than one task if matched")]
|
||||||
many: bool,
|
many: bool,
|
||||||
}
|
},
|
||||||
|
/// change existing memo
|
||||||
|
Edit {
|
||||||
|
search: String,
|
||||||
|
#[clap(short, long, help = "set memo message")]
|
||||||
|
body: Option<String>,
|
||||||
|
#[clap(short, long, help = "set due time relative to now")]
|
||||||
|
due: Option<String>, // TODO allow to pass date
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -71,7 +80,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
let txt = body.join(" ");
|
let txt = body.join(" ");
|
||||||
storage.add(txt.as_str(), due_date).unwrap();
|
storage.add(txt.as_str(), due_date).unwrap();
|
||||||
println!("[+] new memo: {}", txt);
|
println!("{} new memo: {}", "[+]".bold(), txt);
|
||||||
}
|
}
|
||||||
Some(Commands::Done { search, many }) => {
|
Some(Commands::Done { search, many }) => {
|
||||||
let rex = Regex::new(search.as_str());
|
let rex = Regex::new(search.as_str());
|
||||||
|
@ -101,6 +110,26 @@ fn main() {
|
||||||
println!("[!] invalid regex");
|
println!("[!] invalid regex");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some(Commands::Edit { search, body, due }) => {
|
||||||
|
let mut m = find_by_regex(
|
||||||
|
regex::Regex::new(search.as_str()).unwrap(),
|
||||||
|
storage.all(false).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(b) = body {
|
||||||
|
m.body = b;
|
||||||
|
}
|
||||||
|
if let Some(d) = due {
|
||||||
|
if d == "null" || d == "none" {
|
||||||
|
m.due = None
|
||||||
|
} else {
|
||||||
|
m.due = Some(Utc::now() + parse_human_duration(d.as_str()).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storage.set(&m).unwrap();
|
||||||
|
println!("[>] updated memo\n{}", m.human());
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
let all = storage.all(args.old).unwrap();
|
let all = storage.all(args.old).unwrap();
|
||||||
let mut builder = String::new();
|
let mut builder = String::new();
|
||||||
|
@ -119,11 +148,12 @@ fn main() {
|
||||||
let n = libnotify::Notification::new(
|
let n = libnotify::Notification::new(
|
||||||
format!("memo-cli | {}", Local::now().format("%a %d/%m, %H:%M")).as_str(),
|
format!("memo-cli | {}", Local::now().format("%a %d/%m, %H:%M")).as_str(),
|
||||||
Some(builder.as_str()),
|
Some(builder.as_str()),
|
||||||
None
|
None,
|
||||||
);
|
);
|
||||||
n.show().unwrap();
|
n.show().unwrap();
|
||||||
libnotify::uninit();
|
libnotify::uninit();
|
||||||
} else {
|
} else {
|
||||||
|
println!("{}", "memo-cli".bold());
|
||||||
print!("{}", builder);
|
print!("{}", builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ impl fmt::Display for Memo {
|
||||||
pub trait MemoStorage {
|
pub trait MemoStorage {
|
||||||
fn all(&self, done: bool) -> Result<Vec<Memo>, Error>;
|
fn all(&self, done: bool) -> Result<Vec<Memo>, Error>;
|
||||||
fn add(&self, body: &str, due: Option<DateTime<Utc>>) -> Result<(), Error>;
|
fn add(&self, body: &str, due: Option<DateTime<Utc>>) -> Result<(), Error>;
|
||||||
|
fn set(&self, memo: &Memo) -> Result<bool, Error>;
|
||||||
fn del(&self, id: u32) -> Result<bool, Error>;
|
fn del(&self, id: u32) -> Result<bool, Error>;
|
||||||
fn get(&self, id: u32) -> Result<Memo, Error>;
|
fn get(&self, id: u32) -> Result<Memo, Error>;
|
||||||
}
|
}
|
||||||
|
@ -109,6 +110,18 @@ impl MemoStorage for SQLiteStorage {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set(&self, memo: &Memo) -> Result<bool, Error> {
|
||||||
|
let count = self.conn.execute(
|
||||||
|
"UPDATE memo SET body = ?, due = ? WHERE id = ?",
|
||||||
|
params![memo.body, memo.due, memo.id],
|
||||||
|
)?;
|
||||||
|
if count > 0 {
|
||||||
|
return Ok(true);
|
||||||
|
} else {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn del(&self, id: u32) -> Result<bool, Error> {
|
fn del(&self, id: u32) -> Result<bool, Error> {
|
||||||
let count = self
|
let count = self
|
||||||
.conn
|
.conn
|
||||||
|
|
20
src/utils.rs
20
src/utils.rs
|
@ -63,8 +63,24 @@ pub fn parse_human_duration(input: &str) -> Result<Duration, Error> {
|
||||||
return Ok(Duration::seconds(secs));
|
return Ok(Duration::seconds(secs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_by_regex(re: Regex, memos: Vec<Memo>) -> Option<Memo> {
|
||||||
|
let mut found = false;
|
||||||
|
let mut out: Option<Memo> = None;
|
||||||
|
for memo in memos {
|
||||||
|
if re.is_match(memo.body.as_str()) {
|
||||||
|
if found {
|
||||||
|
return None; // there's at least one duplicate
|
||||||
|
} else {
|
||||||
|
out = Some(memo);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO is it possible to make this a method?
|
// TODO is it possible to make this a method?
|
||||||
pub fn vec_to_str<T: std::fmt::Display>(arr: &Vec<T>) -> String {
|
/* pub fn vec_to_str<T: std::fmt::Display>(arr: &Vec<T>) -> String {
|
||||||
let mut out = String::default();
|
let mut out = String::default();
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
out += "[";
|
out += "[";
|
||||||
|
@ -78,4 +94,4 @@ pub fn vec_to_str<T: std::fmt::Display>(arr: &Vec<T>) -> String {
|
||||||
}
|
}
|
||||||
out += " ]";
|
out += " ]";
|
||||||
return out;
|
return out;
|
||||||
}
|
} */
|
||||||
|
|
Loading…
Reference in a new issue