mirror of
https://git.alemi.dev/memo-cli.git
synced 2024-11-22 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 utils;
|
||||
|
||||
use chrono::{DateTime, Utc, Local};
|
||||
use chrono::{DateTime, Local, Utc};
|
||||
use clap::{Parser, Subcommand};
|
||||
use colored::Colorize;
|
||||
use const_format::concatcp;
|
||||
use git_version::git_version;
|
||||
use regex::Regex;
|
||||
use storage::{open_sqlite_storage, Memo, MemoStorage};
|
||||
use utils::{parse_human_duration, HumanDisplay};
|
||||
use git_version::git_version;
|
||||
use const_format::concatcp;
|
||||
use utils::{find_by_regex, parse_human_duration, HumanDisplay};
|
||||
|
||||
const GIT_VERSION: &str = git_version!();
|
||||
const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
@ -47,7 +48,15 @@ enum Commands {
|
|||
search: String,
|
||||
#[clap(long, help = "delete more than one task if matched")]
|
||||
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() {
|
||||
|
@ -71,7 +80,7 @@ fn main() {
|
|||
}
|
||||
let txt = body.join(" ");
|
||||
storage.add(txt.as_str(), due_date).unwrap();
|
||||
println!("[+] new memo: {}", txt);
|
||||
println!("{} new memo: {}", "[+]".bold(), txt);
|
||||
}
|
||||
Some(Commands::Done { search, many }) => {
|
||||
let rex = Regex::new(search.as_str());
|
||||
|
@ -101,6 +110,26 @@ fn main() {
|
|||
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 => {
|
||||
let all = storage.all(args.old).unwrap();
|
||||
let mut builder = String::new();
|
||||
|
@ -119,11 +148,12 @@ fn main() {
|
|||
let n = libnotify::Notification::new(
|
||||
format!("memo-cli | {}", Local::now().format("%a %d/%m, %H:%M")).as_str(),
|
||||
Some(builder.as_str()),
|
||||
None
|
||||
None,
|
||||
);
|
||||
n.show().unwrap();
|
||||
libnotify::uninit();
|
||||
} else {
|
||||
println!("{}", "memo-cli".bold());
|
||||
print!("{}", builder);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ impl fmt::Display for Memo {
|
|||
pub trait MemoStorage {
|
||||
fn all(&self, done: bool) -> Result<Vec<Memo>, 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 get(&self, id: u32) -> Result<Memo, Error>;
|
||||
}
|
||||
|
@ -109,6 +110,18 @@ impl MemoStorage for SQLiteStorage {
|
|||
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> {
|
||||
let count = self
|
||||
.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));
|
||||
}
|
||||
|
||||
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?
|
||||
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 first = true;
|
||||
out += "[";
|
||||
|
@ -78,4 +94,4 @@ pub fn vec_to_str<T: std::fmt::Display>(arr: &Vec<T>) -> String {
|
|||
}
|
||||
out += " ]";
|
||||
return out;
|
||||
}
|
||||
} */
|
||||
|
|
Loading…
Reference in a new issue