From 47243330a917b05e737e63ed7fcc976eea707dd5 Mon Sep 17 00:00:00 2001 From: Kiyomichi Kosaka Date: Sat, 3 Dec 2022 20:37:41 +0000 Subject: [PATCH] Reformat code. --- src/lk.rs | 66 +++++---- src/main.rs | 15 +- src/parser.rs | 364 ++++++++++++++++++++++++++++++++---------------- src/password.rs | 175 +++++++++++++++-------- src/repl.rs | 326 +++++++++++++++++++++++++------------------ src/structs.rs | 75 +++++----- 6 files changed, 638 insertions(+), 383 deletions(-) diff --git a/src/lk.rs b/src/lk.rs index b468d29..e1128ab 100644 --- a/src/lk.rs +++ b/src/lk.rs @@ -1,41 +1,47 @@ -use std::{cell::RefCell, rc::Rc}; +use crate::password::{fix_password_recursion, Password}; +use regex::{Captures, Regex}; use std::collections::HashMap; -use regex::{Regex, Captures}; -use crate::password::{Password, fix_password_recursion}; +use std::{cell::RefCell, rc::Rc}; #[derive(PartialEq, Debug)] pub struct LK { - pub db: HashMap, Rc>>, + pub db: HashMap, Rc>>, } impl LK { - pub fn new() -> Self { - Self { db: HashMap::new() } - } + pub fn new() -> Self { + Self { db: HashMap::new() } + } - pub fn fix_hierarchy(&self) { - lazy_static! { - static ref RE: Regex = Regex::new(r"\s*\^([!-~]+)").unwrap(); - } - for (_, name) in &self.db { - if name.borrow().comment.is_some() { - let mut folder: Option = None; - let prev_comment = name.borrow().comment.as_ref().unwrap().clone(); - let comment = RE.replace(prev_comment.as_str(), |c: &Captures| { folder = Some(c[1].to_string()); "" }); - if folder.is_some() { - let folder_name = folder.unwrap(); - for (_, entry) in &self.db { - if *entry.borrow().name == *folder_name { - let mut tmp = name.borrow_mut(); - tmp.parent = Some(entry.clone()); - if comment.len() == 0 { tmp.comment = None } - else { tmp.comment = Some(comment.to_string()) } - break; - } - } + pub fn fix_hierarchy(&self) { + lazy_static! { + static ref RE: Regex = Regex::new(r"\s*\^([!-~]+)").unwrap(); + } + for (_, name) in &self.db { + if name.borrow().comment.is_some() { + let mut folder: Option = None; + let prev_comment = name.borrow().comment.as_ref().unwrap().clone(); + let comment = RE.replace(prev_comment.as_str(), |c: &Captures| { + folder = Some(c[1].to_string()); + "" + }); + if folder.is_some() { + let folder_name = folder.unwrap(); + for (_, entry) in &self.db { + if *entry.borrow().name == *folder_name { + let mut tmp = name.borrow_mut(); + tmp.parent = Some(entry.clone()); + if comment.len() == 0 { + tmp.comment = None + } else { + tmp.comment = Some(comment.to_string()) + } + break; + } + } + } + } + fix_password_recursion(name.clone()); } - } - fix_password_recursion(name.clone()); } - } } diff --git a/src/main.rs b/src/main.rs index 105acb2..41d3975 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,21 @@ #[macro_use] extern crate lazy_static; -mod structs; -mod password; -mod parser; -mod repl; mod lk; +mod parser; +mod password; +mod repl; +mod structs; -use std::{cell::RefCell, rc::Rc}; use rustyline::Editor; +use std::{cell::RefCell, rc::Rc}; use crate::lk::LK; use crate::repl::LKRead; pub fn main() { let lk = Rc::new(RefCell::new(LK::new())); - let mut lkread = LKRead::new( - Editor::<()>::new().unwrap(), - String::from("❯ "), - lk.clone()); + let mut lkread = LKRead::new(Editor::<()>::new().unwrap(), String::from("❯ "), lk.clone()); while lkread.read().eval().print() { lkread.refresh(); diff --git a/src/parser.rs b/src/parser.rs index fa63400..ebca622 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,130 +1,258 @@ extern crate peg; -use std::{cell::RefCell, rc::Rc}; -use chrono::naive::NaiveDate; -use crate::structs::{Command, LKErr, Mode}; use crate::password::Password; +use crate::structs::{Command, LKErr, Mode}; +use chrono::naive::NaiveDate; +use std::{cell::RefCell, rc::Rc}; -peg::parser!{ - pub grammar command_parser() for str { - pub rule cmd() -> Command<'input> = c:( - help_cmd() - / add_cmd() - / quit_cmd() - / error_cmd() - / ls_cmd() - / mv_cmd() - ) { c } - pub rule name() -> Password = name:(jname() / pname() / mname() / sname()) { name } +peg::parser! { + pub grammar command_parser() for str { + pub rule cmd() -> Command<'input> = c:( + help_cmd() + / add_cmd() + / quit_cmd() + / error_cmd() + / ls_cmd() + / mv_cmd() + ) { c } + pub rule name() -> Password = name:(jname() / pname() / mname() / sname()) { name } - rule _() -> &'input str = s:$((" " / "\t" / "\r" / "\n")+) { s } - rule comment() -> &'input str = _ c:$([' '..='~']+) { c } - rule word() -> &'input str = n:$(['!'..='~']+) { n } - rule num() -> u32 = n:$(['0'..='9']+) {? n.parse().or(Err("not a number")) } - rule pname() -> Password = &(word() _ word() _ num()? mode() _ num() _ date()) pr:word() _ pn:word() _ pl:num()? pm:mode() _ ps:num() _ pd:date() pc:comment()? { - Password { prefix: Some(pr.to_string()), length: pl, name: Rc::new(pn.to_string()), mode: pm, seq: ps, date: pd, parent: None, - comment: match pc { Some(s) => Some(s.to_string()), None => None } } } - rule jname() -> Password = &(word() _ num()? mode() _ num() _ date()) pn:word() _ pl:num()? pm:mode() _ ps:num() _ pd:date() pc:comment()? { - Password { prefix: None, length: pl, name: Rc::new(pn.to_string()), mode: pm, seq: ps, date: pd, parent: None, - comment: match pc { Some(s) => Some(s.to_string()), None => None } } } - rule mname() -> Password = &(word() _ word() _ num()? mode() _ date()) pr:word() _ pn:word() _ pl:num()? pm:mode() _ pd:date() pc:comment()? { - Password { prefix: Some(pr.to_string()), length: pl, name: Rc::new(pn.to_string()), mode: pm, seq: 99, date: pd, parent: None, - comment: match pc { Some(s) => Some(s.to_string()), None => None } } } - rule sname() -> Password = &(word() _ num()? mode() _ date()) pn:word() _ pl:num()? pm:mode() _ pd:date() pc:comment()? { - Password { prefix: None, length: pl, name: Rc::new(pn.to_string()), mode: pm, seq: 99, date: pd, parent: None, - comment: match pc { Some(s) => Some(s.to_string()), None => None } } } - rule date() -> NaiveDate = y:$("-"? ['0'..='9']*<1,4>) "-" m:$(['0'..='9']*<1,2>) "-" d:$(['0'..='9']*<1,2>) {? - let year: i32 = match y.parse() { Ok(n) => n, Err(_) => return Err("year") }; - let month: u32 = match m.parse() { Ok(n) => n, Err(_) => return Err("month") }; - let day: u32 = match d.parse() { Ok(n) => n, Err(_) => return Err("day") }; - NaiveDate::from_ymd_opt(year, month, day).ok_or("date") + rule _() -> &'input str = s:$((" " / "\t" / "\r" / "\n")+) { s } + rule comment() -> &'input str = _ c:$([' '..='~']+) { c } + rule word() -> &'input str = n:$(['!'..='~']+) { n } + rule num() -> u32 = n:$(['0'..='9']+) {? n.parse().or(Err("not a number")) } + rule pname() -> Password = &(word() _ word() _ num()? mode() _ num() _ date()) pr:word() _ pn:word() _ pl:num()? pm:mode() _ ps:num() _ pd:date() pc:comment()? { + Password { prefix: Some(pr.to_string()), length: pl, name: Rc::new(pn.to_string()), mode: pm, seq: ps, date: pd, parent: None, + comment: match pc { Some(s) => Some(s.to_string()), None => None } } } + rule jname() -> Password = &(word() _ num()? mode() _ num() _ date()) pn:word() _ pl:num()? pm:mode() _ ps:num() _ pd:date() pc:comment()? { + Password { prefix: None, length: pl, name: Rc::new(pn.to_string()), mode: pm, seq: ps, date: pd, parent: None, + comment: match pc { Some(s) => Some(s.to_string()), None => None } } } + rule mname() -> Password = &(word() _ word() _ num()? mode() _ date()) pr:word() _ pn:word() _ pl:num()? pm:mode() _ pd:date() pc:comment()? { + Password { prefix: Some(pr.to_string()), length: pl, name: Rc::new(pn.to_string()), mode: pm, seq: 99, date: pd, parent: None, + comment: match pc { Some(s) => Some(s.to_string()), None => None } } } + rule sname() -> Password = &(word() _ num()? mode() _ date()) pn:word() _ pl:num()? pm:mode() _ pd:date() pc:comment()? { + Password { prefix: None, length: pl, name: Rc::new(pn.to_string()), mode: pm, seq: 99, date: pd, parent: None, + comment: match pc { Some(s) => Some(s.to_string()), None => None } } } + rule date() -> NaiveDate = y:$("-"? ['0'..='9']*<1,4>) "-" m:$(['0'..='9']*<1,2>) "-" d:$(['0'..='9']*<1,2>) {? + let year: i32 = match y.parse() { Ok(n) => n, Err(_) => return Err("year") }; + let month: u32 = match m.parse() { Ok(n) => n, Err(_) => return Err("month") }; + let day: u32 = match d.parse() { Ok(n) => n, Err(_) => return Err("day") }; + NaiveDate::from_ymd_opt(year, month, day).ok_or("date") + } + rule umode() -> Mode = ("U" / "u") m:$("R" / "r" / "N" / "n" / "H" / "h" / "B" / "b") {? + match m.to_uppercase().as_str() { + "R" => Ok(Mode::RegularUpcase), + "N" => Ok(Mode::NoSpaceUpcase), + "H" => Ok(Mode::HexUpcase), + "B" => Ok(Mode::Base64Upcase), + _ => Err("unknown mode"), + } + } + rule rmode() -> Mode = m:$("R" / "r" / "U" / "u" / "N" / "n" / "H" / "h" / "B" / "b" / "D" / "d") {? + match m.to_uppercase().as_str() { + "R" => Ok(Mode::Regular), + "N" => Ok(Mode::NoSpace), + "U" => Ok(Mode::RegularUpcase), + "H" => Ok(Mode::Hex), + "B" => Ok(Mode::Base64), + "D" => Ok(Mode::Decimal), + _ => Err("unknown mode"), + } + } + rule mode() -> Mode = m:(umode() / rmode()) { m } + rule help_cmd() -> Command<'input> = "help" { Command::Help } + rule quit_cmd() -> Command<'input> = "quit" { Command::Quit } + rule ls_cmd() -> Command<'input> = "ls" { Command::Ls } + rule add_cmd() -> Command<'input> = "add" _ name:name() { Command::Add(Rc::new(RefCell::new(name))) } + rule error_cmd() -> Command<'input> = "error" _ e:$(([' '..='~'])+) { Command::Error(LKErr::Error(e)) } + rule mv_cmd() -> Command<'input> = "mv" _ name:word() _ folder:word() { Command::Mv(name.to_string(), folder.to_string()) } } - rule umode() -> Mode = ("U" / "u") m:$("R" / "r" / "N" / "n" / "H" / "h" / "B" / "b") {? - match m.to_uppercase().as_str() { - "R" => Ok(Mode::RegularUpcase), - "N" => Ok(Mode::NoSpaceUpcase), - "H" => Ok(Mode::HexUpcase), - "B" => Ok(Mode::Base64Upcase), - _ => Err("unknown mode"), - } - } - rule rmode() -> Mode = m:$("R" / "r" / "U" / "u" / "N" / "n" / "H" / "h" / "B" / "b" / "D" / "d") {? - match m.to_uppercase().as_str() { - "R" => Ok(Mode::Regular), - "N" => Ok(Mode::NoSpace), - "U" => Ok(Mode::RegularUpcase), - "H" => Ok(Mode::Hex), - "B" => Ok(Mode::Base64), - "D" => Ok(Mode::Decimal), - _ => Err("unknown mode"), - } - } - rule mode() -> Mode = m:(umode() / rmode()) { m } - rule help_cmd() -> Command<'input> = "help" { Command::Help } - rule quit_cmd() -> Command<'input> = "quit" { Command::Quit } - rule ls_cmd() -> Command<'input> = "ls" { Command::Ls } - rule add_cmd() -> Command<'input> = "add" _ name:name() { Command::Add(Rc::new(RefCell::new(name))) } - rule error_cmd() -> Command<'input> = "error" _ e:$(([' '..='~'])+) { Command::Error(LKErr::Error(e)) } - rule mv_cmd() -> Command<'input> = "mv" _ name:word() _ folder:word() { Command::Mv(name.to_string(), folder.to_string()) } - } } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn parse_password_test() { - assert_eq!(command_parser::name("ableton89 R 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: None, mode: Mode::Regular, - length: None, seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) })); - assert_eq!(command_parser::name("ableton89 U 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: None, mode: Mode::RegularUpcase, - length: None, seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) })); - assert_eq!(command_parser::name("ableton89 U 2020-12-09"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: None, mode: Mode::RegularUpcase, - length: None, seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), comment: None })); - assert_eq!(command_parser::name("#W9 ableton89 R 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: Some("#W9".to_string()), mode: Mode::Regular, - length: None, seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) })); - assert_eq!(command_parser::name("#W9 ableton89 N 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: Some("#W9".to_string()), mode: Mode::NoSpace, - length: None, seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) })); - assert_eq!(command_parser::name("#W9 ableton89 UN 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: Some("#W9".to_string()), mode: Mode::NoSpaceUpcase, - length: None, seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) })); - assert_eq!(command_parser::name("#W9 ableton89 20R 99 2020-12-09 a b c"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: Some("#W9".to_string()), mode: Mode::Regular, - length: Some(20), seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("a b c".to_string()) })); - assert_eq!(command_parser::name("#W9 ableton89 20UR 99 2020-12-09 a b c"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: Some("#W9".to_string()), mode: Mode::RegularUpcase, - length: Some(20), seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("a b c".to_string()) })); - assert_eq!(command_parser::name("#W9 ableton89 20UH 99 2020-12-09 a b c"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: Some("#W9".to_string()), mode: Mode::HexUpcase, - length: Some(20), seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("a b c".to_string()) })); - assert_eq!(command_parser::name("#W9 ableton89 20UB 99 2020-12-09 a b c"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: Some("#W9".to_string()), mode: Mode::Base64Upcase, - length: Some(20), seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("a b c".to_string()) })); - assert_eq!(command_parser::name("#W9 ableton89 20D 99 2020-12-09 a b c"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: Some("#W9".to_string()), mode: Mode::Decimal, - length: Some(20), seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("a b c".to_string()) })); - assert_eq!(command_parser::name("ableton89 20D 98 2020-12-09 a b c"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: None, mode: Mode::Decimal, - length: Some(20), seq: 98, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("a b c".to_string()) })); - assert_eq!(command_parser::name("ableton89 20D 2020-12-09 a b c"), - Ok(Password { name: Rc::new("ableton89".to_string()), parent: None, prefix: None, mode: Mode::Decimal, - length: Some(20), seq: 99, date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), - comment: Some("a b c".to_string()) })); - } + #[test] + fn parse_password_test() { + assert_eq!( + command_parser::name( + "ableton89 R 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com" + ), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: None, + mode: Mode::Regular, + length: None, + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) + }) + ); + assert_eq!( + command_parser::name( + "ableton89 U 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com" + ), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: None, + mode: Mode::RegularUpcase, + length: None, + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) + }) + ); + assert_eq!( + command_parser::name("ableton89 U 2020-12-09"), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: None, + mode: Mode::RegularUpcase, + length: None, + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: None + }) + ); + assert_eq!( + command_parser::name( + "#W9 ableton89 R 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com" + ), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: Some("#W9".to_string()), + mode: Mode::Regular, + length: None, + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) + }) + ); + assert_eq!( + command_parser::name( + "#W9 ableton89 N 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com" + ), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: Some("#W9".to_string()), + mode: Mode::NoSpace, + length: None, + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) + }) + ); + assert_eq!( + command_parser::name( + "#W9 ableton89 UN 99 2020-12-09 xx.ableton@domain.info https://www.ableton.com" + ), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: Some("#W9".to_string()), + mode: Mode::NoSpaceUpcase, + length: None, + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) + }) + ); + assert_eq!( + command_parser::name("#W9 ableton89 20R 99 2020-12-09 a b c"), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: Some("#W9".to_string()), + mode: Mode::Regular, + length: Some(20), + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("a b c".to_string()) + }) + ); + assert_eq!( + command_parser::name("#W9 ableton89 20UR 99 2020-12-09 a b c"), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: Some("#W9".to_string()), + mode: Mode::RegularUpcase, + length: Some(20), + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("a b c".to_string()) + }) + ); + assert_eq!( + command_parser::name("#W9 ableton89 20UH 99 2020-12-09 a b c"), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: Some("#W9".to_string()), + mode: Mode::HexUpcase, + length: Some(20), + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("a b c".to_string()) + }) + ); + assert_eq!( + command_parser::name("#W9 ableton89 20UB 99 2020-12-09 a b c"), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: Some("#W9".to_string()), + mode: Mode::Base64Upcase, + length: Some(20), + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("a b c".to_string()) + }) + ); + assert_eq!( + command_parser::name("#W9 ableton89 20D 99 2020-12-09 a b c"), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: Some("#W9".to_string()), + mode: Mode::Decimal, + length: Some(20), + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("a b c".to_string()) + }) + ); + assert_eq!( + command_parser::name("ableton89 20D 98 2020-12-09 a b c"), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: None, + mode: Mode::Decimal, + length: Some(20), + seq: 98, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("a b c".to_string()) + }) + ); + assert_eq!( + command_parser::name("ableton89 20D 2020-12-09 a b c"), + Ok(Password { + name: Rc::new("ableton89".to_string()), + parent: None, + prefix: None, + mode: Mode::Decimal, + length: Some(20), + seq: 99, + date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), + comment: Some("a b c".to_string()) + }) + ); + } } diff --git a/src/password.rs b/src/password.rs index d34b2a6..a80f961 100644 --- a/src/password.rs +++ b/src/password.rs @@ -1,80 +1,139 @@ -use std::{cell::RefCell, rc::Rc}; -use chrono::naive::NaiveDate; use crate::structs::Mode; +use chrono::naive::NaiveDate; +use std::{cell::RefCell, rc::Rc}; #[derive(PartialEq, Debug)] pub struct Password { - pub parent: Option>>, - pub prefix: Option, - pub name: Rc, - pub length: Option, - pub mode: Mode, - pub seq: u32, - pub date: NaiveDate, - pub comment: Option, + pub parent: Option>>, + pub prefix: Option, + pub name: Rc, + pub length: Option, + pub mode: Mode, + pub seq: u32, + pub date: NaiveDate, + pub comment: Option, } impl Password { - pub fn new(prefix: Option, name: String, mode: Mode, date: NaiveDate) -> Password { - Password { prefix, mode, date, - parent: None, - name: Rc::new(name), - length: None, - seq: 99, - comment: None } - } + pub fn new(prefix: Option, name: String, mode: Mode, date: NaiveDate) -> Password { + Password { + prefix, + mode, + date, + parent: None, + name: Rc::new(name), + length: None, + seq: 99, + comment: None, + } + } } impl std::string::ToString for Password { - fn to_string(&self) -> String { - let prefix = match self.prefix.as_ref() { Some(s) => format!("{} ", s), None => "".to_string() }; - let length = match self.length { Some(l) => format!("{}", l), None => "".to_string() }; - let comment = match self.comment.as_ref() { Some(s) => format!(" {}", s), None => "".to_string() }; - let parent = match &self.parent { Some(s) => format!(" ^{}", s.borrow().name), None => "".to_string() }; - format!("{}{} {}{} {} {}{}{}", prefix, self.name, length, self.mode, self.seq, self.date, comment, parent) - } + fn to_string(&self) -> String { + let prefix = match self.prefix.as_ref() { + Some(s) => format!("{} ", s), + None => "".to_string(), + }; + let length = match self.length { + Some(l) => format!("{}", l), + None => "".to_string(), + }; + let comment = match self.comment.as_ref() { + Some(s) => format!(" {}", s), + None => "".to_string(), + }; + let parent = match &self.parent { + Some(s) => format!(" ^{}", s.borrow().name), + None => "".to_string(), + }; + format!( + "{}{} {}{} {} {}{}{}", + prefix, self.name, length, self.mode, self.seq, self.date, comment, parent + ) + } } pub fn fix_password_recursion(entry: Rc>) { - let mut t1 = entry.clone(); - let mut t2 = entry; - let mut t3: Option>> = None; - loop { - t2 = match &t2.clone().borrow().parent { Some(o) => o.clone(), None => break }; - if std::ptr::eq(&*t1.borrow(), &*t2.borrow()) { t3 = Some(t2.clone()); break; } - t1 = match &t1.clone().borrow().parent { Some(o) => o.clone(), None => break }; - t2 = match &t2.clone().borrow().parent { Some(o) => o.clone(), None => break }; - if std::ptr::eq(&*t1.borrow(), &*t2.borrow()) { t3 = Some(t2.clone()); break; } - } - match t3 { - Some(o) => o.borrow_mut().parent = None, - None => (), - } + let mut t1 = entry.clone(); + let mut t2 = entry; + let mut t3: Option>> = None; + loop { + t2 = match &t2.clone().borrow().parent { + Some(o) => o.clone(), + None => break, + }; + if std::ptr::eq(&*t1.borrow(), &*t2.borrow()) { + t3 = Some(t2.clone()); + break; + } + t1 = match &t1.clone().borrow().parent { + Some(o) => o.clone(), + None => break, + }; + t2 = match &t2.clone().borrow().parent { + Some(o) => o.clone(), + None => break, + }; + if std::ptr::eq(&*t1.borrow(), &*t2.borrow()) { + t3 = Some(t2.clone()); + break; + } + } + match t3 { + Some(o) => o.borrow_mut().parent = None, + None => (), + } } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn exec_recursion_test() { - let p1 = Rc::new(RefCell::new(Password::new(None, "p1".to_string(), Mode::Regular, NaiveDate::from_ymd_opt(2022, 12, 3).unwrap()))); + #[test] + fn exec_recursion_test() { + let p1 = Rc::new(RefCell::new(Password::new( + None, + "p1".to_string(), + Mode::Regular, + NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), + ))); - p1.borrow_mut().parent = Some(p1.clone()); - fix_password_recursion(p1.clone()); - assert_eq!(p1.borrow().parent, None); + p1.borrow_mut().parent = Some(p1.clone()); + fix_password_recursion(p1.clone()); + assert_eq!(p1.borrow().parent, None); - let p2 = Rc::new(RefCell::new(Password::new(None, "p2".to_string(), Mode::Regular, NaiveDate::from_ymd_opt(2022, 12, 3).unwrap()))); - p2.borrow_mut().parent = Some(p1.clone()); - let p3 = Rc::new(RefCell::new(Password::new(None, "p3".to_string(), Mode::Regular, NaiveDate::from_ymd_opt(2022, 12, 3).unwrap()))); - p3.borrow_mut().parent = Some(p2.clone()); - let p4 = Rc::new(RefCell::new(Password::new(None, "p4".to_string(), Mode::Regular, NaiveDate::from_ymd_opt(2022, 12, 3).unwrap()))); - p4.borrow_mut().parent = Some(p3.clone()); - let p5 = Rc::new(RefCell::new(Password::new(None, "p5".to_string(), Mode::Regular, NaiveDate::from_ymd_opt(2022, 12, 3).unwrap()))); - p5.borrow_mut().parent = Some(p4.clone()); + let p2 = Rc::new(RefCell::new(Password::new( + None, + "p2".to_string(), + Mode::Regular, + NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), + ))); + p2.borrow_mut().parent = Some(p1.clone()); + let p3 = Rc::new(RefCell::new(Password::new( + None, + "p3".to_string(), + Mode::Regular, + NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), + ))); + p3.borrow_mut().parent = Some(p2.clone()); + let p4 = Rc::new(RefCell::new(Password::new( + None, + "p4".to_string(), + Mode::Regular, + NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), + ))); + p4.borrow_mut().parent = Some(p3.clone()); + let p5 = Rc::new(RefCell::new(Password::new( + None, + "p5".to_string(), + Mode::Regular, + NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), + ))); + p5.borrow_mut().parent = Some(p4.clone()); - p1.borrow_mut().parent = Some(p3.clone()); - fix_password_recursion(p5.clone()); - assert_eq!(p3.borrow().parent, None); - } + p1.borrow_mut().parent = Some(p3.clone()); + fix_password_recursion(p5.clone()); + assert_eq!(p3.borrow().parent, None); + } } diff --git a/src/repl.rs b/src/repl.rs index aeac172..93a5f14 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -1,128 +1,146 @@ +use home::home_dir; use rustyline::Editor; use std::{cell::RefCell, rc::Rc}; -use home::home_dir; use crate::lk::LK; -use crate::structs::{LKErr, Command}; -use crate::password::fix_password_recursion; use crate::parser::command_parser; +use crate::password::fix_password_recursion; +use crate::structs::{Command, LKErr}; #[derive(Debug)] pub struct LKRead { - rl: Editor::<()>, - prompt: String, - state: Rc>, - cmd: String, + rl: Editor<()>, + prompt: String, + state: Rc>, + cmd: String, } #[derive(Debug)] pub struct LKEval<'a> { - cmd: Command<'a>, - state: Rc>, + cmd: Command<'a>, + state: Rc>, } #[derive(Debug, PartialEq)] pub struct LKPrint { - out: Vec, - quit: bool, - state: Rc>, + out: Vec, + quit: bool, + state: Rc>, } impl LKRead { - pub fn new(rl: Editor::<()>, prompt: String, state: Rc>) -> Self { - Self { rl, prompt, state, cmd: "".to_string() } - } - - pub fn read(&mut self) -> LKEval { - let history_file_path = home_dir().unwrap().join(".lesskey_history"); - let history_file = history_file_path.as_path().to_str().unwrap(); - self.rl.clear_history(); - match self.rl.load_history(&history_file) { - Ok(_) => (), - Err(_) => { self.rl.add_history_entry("ls"); () } + pub fn new(rl: Editor<()>, prompt: String, state: Rc>) -> Self { + Self { + rl, + prompt, + state, + cmd: "".to_string(), + } } - self.cmd = match self.rl.readline(&*self.prompt) { - Ok(str) => str, - Err(err) => return LKEval::new(Command::Error(LKErr::ReadError(err.to_string())), self.state.clone()), - }; - self.rl.add_history_entry(self.cmd.as_str()); - match self.rl.save_history(&history_file) { Ok(_) => (), Err(_) => () } - match command_parser::cmd(self.cmd.as_str()) { - Ok(cmd) => LKEval::new(cmd, self.state.clone()), - Err(err) => LKEval::new(Command::Error(LKErr::ParseError(err)), self.state.clone()), + + pub fn read(&mut self) -> LKEval { + let history_file_path = home_dir().unwrap().join(".lesskey_history"); + let history_file = history_file_path.as_path().to_str().unwrap(); + self.rl.clear_history(); + match self.rl.load_history(&history_file) { + Ok(_) => (), + Err(_) => { + self.rl.add_history_entry("ls"); + () + } + } + self.cmd = match self.rl.readline(&*self.prompt) { + Ok(str) => str, + Err(err) => { + return LKEval::new( + Command::Error(LKErr::ReadError(err.to_string())), + self.state.clone(), + ) + } + }; + self.rl.add_history_entry(self.cmd.as_str()); + match self.rl.save_history(&history_file) { + Ok(_) => (), + Err(_) => (), + } + match command_parser::cmd(self.cmd.as_str()) { + Ok(cmd) => LKEval::new(cmd, self.state.clone()), + Err(err) => LKEval::new(Command::Error(LKErr::ParseError(err)), self.state.clone()), + } } - } - pub fn refresh(&mut self) { + pub fn refresh(&mut self) {} - } - - pub fn quit(&mut self) { - - } + pub fn quit(&mut self) {} } impl<'a> LKEval<'a> { - pub fn new(cmd: Command<'a>, state: Rc>) -> Self { Self { cmd, state } } - - pub fn eval(&mut self) -> LKPrint { - let mut out: Vec = vec![]; - let mut quit: bool = false; - - match &self.cmd { - Command::Quit => { - out.push("Bye!".to_string()); - quit = true; - }, - Command::Ls => { - for (_, name) in &self.state.borrow().db { - out.push(name.borrow().to_string()); - } - out.sort(); - }, - Command::Add(name) => { - if self.state.borrow().db.get(&name.borrow().name).is_some() { - out.push("error: password already exist".to_string()); - } else { - self.state.borrow_mut().db.insert(name.borrow().name.clone(), name.clone()); - self.state.borrow().fix_hierarchy(); - } - }, - Command::Help => { - out.push("HELP".to_string()); - }, - Command::Mv(name, folder) => { - for (_, tmp) in &self.state.borrow().db { - if *tmp.borrow().name == *name { - if folder == "/" { tmp.borrow_mut().parent = None } - else { - for (_, fld) in &self.state.borrow().db { - if *fld.borrow().name == *folder { - tmp.borrow_mut().parent = Some(fld.clone()); - fix_password_recursion(tmp.clone()); - break; - } - } - } - break; - } - } - }, - Command::Error(err) => { - match err { - LKErr::ParseError(e) => { out.push(e.to_string()) }, - LKErr::ReadError(e) => { out.push(e.to_string()) }, - LKErr::Error(e) => { out.push(format!("error: {}", e.to_string())) }, - } - } + pub fn new(cmd: Command<'a>, state: Rc>) -> Self { + Self { cmd, state } } - LKPrint::new(out, quit, self.state.clone()) - } + pub fn eval(&mut self) -> LKPrint { + let mut out: Vec = vec![]; + let mut quit: bool = false; + + match &self.cmd { + Command::Quit => { + out.push("Bye!".to_string()); + quit = true; + } + Command::Ls => { + for (_, name) in &self.state.borrow().db { + out.push(name.borrow().to_string()); + } + out.sort(); + } + Command::Add(name) => { + if self.state.borrow().db.get(&name.borrow().name).is_some() { + out.push("error: password already exist".to_string()); + } else { + self.state + .borrow_mut() + .db + .insert(name.borrow().name.clone(), name.clone()); + self.state.borrow().fix_hierarchy(); + } + } + Command::Help => { + out.push("HELP".to_string()); + } + Command::Mv(name, folder) => { + for (_, tmp) in &self.state.borrow().db { + if *tmp.borrow().name == *name { + if folder == "/" { + tmp.borrow_mut().parent = None + } else { + for (_, fld) in &self.state.borrow().db { + if *fld.borrow().name == *folder { + tmp.borrow_mut().parent = Some(fld.clone()); + fix_password_recursion(tmp.clone()); + break; + } + } + } + break; + } + } + } + Command::Error(err) => match err { + LKErr::ParseError(e) => out.push(e.to_string()), + LKErr::ReadError(e) => out.push(e.to_string()), + LKErr::Error(e) => out.push(format!("error: {}", e.to_string())), + }, + } + + LKPrint::new(out, quit, self.state.clone()) + } } impl LKPrint { - pub fn new(out: Vec, quit: bool, state: Rc>) -> Self { Self { out, quit, state } } + pub fn new(out: Vec, quit: bool, state: Rc>) -> Self { + Self { out, quit, state } + } pub fn print(&mut self) -> bool { for line in &self.out { @@ -134,44 +152,86 @@ impl LKPrint { #[cfg(test)] mod tests { - use super::*; - use std::collections::HashMap; - use chrono::naive::NaiveDate; - use crate::structs::Mode; - use crate::password::Password; + use super::*; + use crate::password::Password; + use crate::structs::Mode; + use chrono::naive::NaiveDate; + use std::collections::HashMap; - #[test] - fn exec_cmds_basic() { - let lk = Rc::new(RefCell::new(LK::new())); - assert_eq!(LKEval::new(Command::Ls, lk.clone()).eval(), LKPrint::new(vec![], false, lk.clone())); - let pwd1 = Rc::new(RefCell::new(Password { name: Rc::new("t1".to_string()), - prefix: None, length: None, - mode: Mode::Regular, seq: 99, - date: NaiveDate::from_ymd_opt(2022, 12, 30).unwrap(), - comment: Some("comment".to_string()), - parent: None })); - assert_eq!(LKEval::new(Command::Add(pwd1.clone()), lk.clone()).eval().state.borrow().db, - { let mut db = HashMap::new(); - db.insert(pwd1.borrow().name.clone(), pwd1.clone()); - db }); - assert_eq!(LKEval::new(Command::Ls, lk.clone()).eval(), - LKPrint::new(vec!["t1 R 99 2022-12-30 comment".to_string()], false, lk.clone())); - assert_eq!(LKEval::new(Command::Quit, lk.clone()).eval(), - LKPrint::new(vec!["Bye!".to_string()], true, lk.clone())); - let pwd2 = Rc::new(RefCell::new(Password { name: Rc::new("t2".to_string()), - prefix: None, length: None, - mode: Mode::Regular, seq: 99, - date: NaiveDate::from_ymd_opt(2022, 12, 31).unwrap(), - comment: Some("bli blup".to_string()), - parent: None })); - assert_eq!(LKEval::new(Command::Add(pwd2.clone()), lk.clone()).eval().state.borrow().db, - { let mut db = HashMap::new(); - db.insert(pwd1.borrow().name.clone(), pwd1.clone()); - db.insert(pwd2.borrow().name.clone(), pwd2.clone()); - db }); - assert_eq!(LKEval::new(Command::Ls, lk.clone()).eval(), - LKPrint::new(vec!["t1 R 99 2022-12-30 comment".to_string(), - "t2 R 99 2022-12-31 bli blup".to_string()], - false, lk.clone())); - } + #[test] + fn exec_cmds_basic() { + let lk = Rc::new(RefCell::new(LK::new())); + assert_eq!( + LKEval::new(Command::Ls, lk.clone()).eval(), + LKPrint::new(vec![], false, lk.clone()) + ); + let pwd1 = Rc::new(RefCell::new(Password { + name: Rc::new("t1".to_string()), + prefix: None, + length: None, + mode: Mode::Regular, + seq: 99, + date: NaiveDate::from_ymd_opt(2022, 12, 30).unwrap(), + comment: Some("comment".to_string()), + parent: None, + })); + assert_eq!( + LKEval::new(Command::Add(pwd1.clone()), lk.clone()) + .eval() + .state + .borrow() + .db, + { + let mut db = HashMap::new(); + db.insert(pwd1.borrow().name.clone(), pwd1.clone()); + db + } + ); + assert_eq!( + LKEval::new(Command::Ls, lk.clone()).eval(), + LKPrint::new( + vec!["t1 R 99 2022-12-30 comment".to_string()], + false, + lk.clone() + ) + ); + assert_eq!( + LKEval::new(Command::Quit, lk.clone()).eval(), + LKPrint::new(vec!["Bye!".to_string()], true, lk.clone()) + ); + let pwd2 = Rc::new(RefCell::new(Password { + name: Rc::new("t2".to_string()), + prefix: None, + length: None, + mode: Mode::Regular, + seq: 99, + date: NaiveDate::from_ymd_opt(2022, 12, 31).unwrap(), + comment: Some("bli blup".to_string()), + parent: None, + })); + assert_eq!( + LKEval::new(Command::Add(pwd2.clone()), lk.clone()) + .eval() + .state + .borrow() + .db, + { + let mut db = HashMap::new(); + db.insert(pwd1.borrow().name.clone(), pwd1.clone()); + db.insert(pwd2.borrow().name.clone(), pwd2.clone()); + db + } + ); + assert_eq!( + LKEval::new(Command::Ls, lk.clone()).eval(), + LKPrint::new( + vec![ + "t1 R 99 2022-12-30 comment".to_string(), + "t2 R 99 2022-12-31 bli blup".to_string() + ], + false, + lk.clone() + ) + ); + } } diff --git a/src/structs.rs b/src/structs.rs index b4d4d18..5915da9 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -1,51 +1,56 @@ -use std::{cell::RefCell, rc::Rc}; use crate::password::Password; +use std::{cell::RefCell, rc::Rc}; #[derive(thiserror::Error, Debug, PartialEq)] pub enum LKErr<'a> { - #[error("Error: {0}")] - Error(&'a str), - #[error("Failed to read the line: {0}")] - ReadError(String), - #[error("Failed to parse: {0}")] - ParseError(peg::error::ParseError), + #[error("Error: {0}")] + Error(&'a str), + #[error("Failed to read the line: {0}")] + ReadError(String), + #[error("Failed to parse: {0}")] + ParseError(peg::error::ParseError), } #[derive(PartialEq, Debug)] pub enum Command<'a> { - Add(Rc>), - Ls, - Mv(String, String), - Error(LKErr<'a>), - Help, - Quit + Add(Rc>), + Ls, + Mv(String, String), + Error(LKErr<'a>), + Help, + Quit, } #[derive(PartialEq, Debug)] pub enum Mode { - Regular, - RegularUpcase, - NoSpace, - NoSpaceUpcase, - Hex, - HexUpcase, - Base64, - Base64Upcase, - Decimal, + Regular, + RegularUpcase, + NoSpace, + NoSpaceUpcase, + Hex, + HexUpcase, + Base64, + Base64Upcase, + Decimal, } impl std::fmt::Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match self { - Mode::Regular => "R", - Mode::RegularUpcase => "UR", - Mode::NoSpace => "N", - Mode::NoSpaceUpcase => "UN", - Mode::Hex => "H", - Mode::HexUpcase => "UH", - Mode::Base64 => "B", - Mode::Base64Upcase => "UB", - Mode::Decimal => "D", - }.to_string()) - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Mode::Regular => "R", + Mode::RegularUpcase => "UR", + Mode::NoSpace => "N", + Mode::NoSpaceUpcase => "UN", + Mode::Hex => "H", + Mode::HexUpcase => "UH", + Mode::Base64 => "B", + Mode::Base64Upcase => "UB", + Mode::Decimal => "D", + } + .to_string() + ) + } }