Split project into three workspaces: hel (the library), helcli (the tool) and helwasm (the wasm code). Move wasm incompatible code to extra modules in utils.rs to be implementable separately for wasm.

This commit is contained in:
Oleksandr Kozachuk
2023-01-01 18:50:16 +01:00
parent cff9e3f90d
commit eced302282
18 changed files with 330 additions and 181 deletions
+2 -25
View File
@@ -1,25 +1,2 @@
[package] [workspace]
name = "hel" members = ["hel", "helcli", "helwasm"]
version = "0.1.0"
authors = ["ok2"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = "0.4.23"
peg = "0.8.1"
anyhow = "1.0.66"
lazy_static = "1.4.0"
regex = "1.6.0"
rustyline = "10.0.0"
thiserror = "1.0.37"
anyerror = "0.1.7"
home = "0.5.4"
sha1 = "0.10.5"
base64 = "0.20.0"
rpassword = "7.2.0"
shlex = "1.1.0"
shellexpand = "3.0.0"
scopeguard = "1.1.0"
rand = "0.8.5"
+31
View File
@@ -0,0 +1,31 @@
[package]
name = "hel"
version = "0.1.0"
authors = ["ok2"]
edition = "2021"
[lib]
name = "hel"
crate-type = ["lib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
peg = "0.8.1"
anyhow = "1.0.66"
lazy_static = "1.4.0"
regex = "1.6.0"
thiserror = "1.0.37"
anyerror = "0.1.7"
sha1 = "0.10.5"
base64 = "0.20.0"
rpassword = "7.2.0"
shlex = "1.1.0"
shellexpand = "3.0.0"
scopeguard = "1.1.0"
[target.'cfg(not(wasm))'.dependencies]
chrono = "0.4.23"
rand = "0.8.5"
home = "0.5.4"
rustyline = "10.0.0"
+2 -4
View File
@@ -1,4 +1,3 @@
use rand::{thread_rng, Rng};
use regex::Regex; use regex::Regex;
use rpassword::prompt_password; use rpassword::prompt_password;
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
@@ -13,7 +12,7 @@ use crate::password::fix_password_recursion;
use crate::password::{Name, Password, PasswordRef}; use crate::password::{Name, Password, PasswordRef};
use crate::repl::LKEval; use crate::repl::LKEval;
use crate::structs::{LKOut, Radix, CORRECT_FILE, DUMP_FILE}; use crate::structs::{LKOut, Radix, CORRECT_FILE, DUMP_FILE};
use crate::utils::{call_cmd_with_input, get_cmd_args_from_command, get_copy_command_from_env}; use crate::utils::{call_cmd_with_input, get_cmd_args_from_command, get_copy_command_from_env, rnd};
impl<'a> LKEval<'a> { impl<'a> LKEval<'a> {
pub fn get_password(&self, name: &String) -> Option<PasswordRef> { pub fn get_password(&self, name: &String) -> Option<PasswordRef> {
@@ -429,7 +428,6 @@ impl<'a> LKEval<'a> {
lazy_static! { lazy_static! {
static ref RE: Regex = Regex::new(r"^.+?(G+|X+)$").unwrap(); static ref RE: Regex = Regex::new(r"^.+?(G+|X+)$").unwrap();
} }
let mut rng = thread_rng();
let num: usize = (*num).try_into().unwrap(); let num: usize = (*num).try_into().unwrap();
let pwd = name.borrow(); let pwd = name.borrow();
let mut genpwds: Vec<PasswordRef> = Vec::new(); let mut genpwds: Vec<PasswordRef> = Vec::new();
@@ -445,7 +443,7 @@ impl<'a> LKEval<'a> {
} }
} else { } else {
let name = pwd.name.trim_end_matches('X'); let name = pwd.name.trim_end_matches('X');
let num = rng.gen_range(1..10_u32.pow(gen.len().try_into().unwrap())); let num = rnd::range(1, 10_u32.pow(gen.len().try_into().unwrap()));
let npwd = Password::from_password(&pwd); let npwd = Password::from_password(&pwd);
npwd.borrow_mut().name = format!("{}{}", name, num).to_string(); npwd.borrow_mut().name = format!("{}{}", name, num).to_string();
genpwds.push(npwd); genpwds.push(npwd);
+15
View File
@@ -0,0 +1,15 @@
#[macro_use]
extern crate lazy_static;
#[allow(unused_imports)]
#[macro_use(defer)]
extern crate scopeguard;
pub mod commands;
pub mod lk;
pub mod parser;
pub mod password;
pub mod repl;
pub mod skey;
pub mod structs;
pub mod utils;
View File
+30 -31
View File
@@ -2,8 +2,7 @@ extern crate peg;
use crate::password::Password; use crate::password::Password;
use crate::structs::{Command, LKErr, Mode}; use crate::structs::{Command, LKErr, Mode};
use chrono::naive::NaiveDate; use crate::utils::date::Date;
use chrono::Local;
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
peg::parser! { peg::parser! {
@@ -42,21 +41,21 @@ peg::parser! {
rule sname() -> Password = &(word() _ num()? mode() _ date()) pn:word() _ pl:num()? pm:mode() _ pd:date() pc:comment()? rule sname() -> Password = &(word() _ num()? mode() _ date()) pn:word() _ pl:num()? pm:mode() _ pd:date() pc:comment()?
{ Password::new(None, pn, pl, pm, 99, pd, pc) } { Password::new(None, pn, pl, pm, 99, pd, pc) }
rule nname() -> Password = &(word() _ num()? mode()) pn:word() _ pl:num()? pm:mode() rule nname() -> Password = &(word() _ num()? mode()) pn:word() _ pl:num()? pm:mode()
{ Password::new(None, pn, pl, pm, 99, Local::now().naive_local().date(), None) } { Password::new(None, pn, pl, pm, 99, Date::now(), None) }
rule qname() -> Password = &(word()) pn:word() rule qname() -> Password = &(word()) pn:word()
{ Password::new(None, pn, None, Mode::NoSpaceCamel, 99, Local::now().naive_local().date(), None) } { Password::new(None, pn, None, Mode::NoSpaceCamel, 99, Date::now(), None) }
pub rule name() -> Password = name:(jname() / pname() / mname() / sname() / nname() / qname())? {? pub rule name() -> Password = name:(jname() / pname() / mname() / sname() / nname() / qname())? {?
match name { Some(n) => Ok(n), None => Err("failed to parse password description") } match name { Some(n) => Ok(n), None => Err("failed to parse password description") }
} }
rule ndate() -> NaiveDate = y:$("-"? ['0'..='9']*<1,4>) "-" m:$(['0'..='9']*<1,2>) "-" d:$(['0'..='9']*<1,2>) {? rule ndate() -> Date = 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 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 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") }; let day: u32 = match d.parse() { Ok(n) => n, Err(_) => return Err("day") };
NaiveDate::from_ymd_opt(year, month, day).ok_or("date") Date::try_new(year, month, day)
} }
rule cdate() -> NaiveDate = "now" { Local::now().naive_local().date() } rule cdate() -> Date = "now" { Date::now() }
rule date() -> NaiveDate = d:(ndate() / cdate()) { d } rule date() -> Date = d:(ndate() / cdate()) { d }
rule umode() -> Mode = ("U" / "u") m:$("R" / "r" / "N" / "n" / "H" / "h" / "B" / "b") {? rule umode() -> Mode = ("U" / "u") m:$("R" / "r" / "N" / "n" / "H" / "h" / "B" / "b") {?
match m.to_uppercase().as_str() { match m.to_uppercase().as_str() {
"R" => Ok(Mode::RegularUpcase), "R" => Ok(Mode::RegularUpcase),
@@ -126,7 +125,7 @@ add t3 C 99 2022-12-14"###
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), }))),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Rc::new(RefCell::new(Password {
@@ -136,7 +135,7 @@ add t3 C 99 2022-12-14"###
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), }))),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Rc::new(RefCell::new(Password {
@@ -146,7 +145,7 @@ add t3 C 99 2022-12-14"###
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))) })))
]) ])
@@ -166,7 +165,7 @@ add t3 C 99 2022-12-14
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), }))),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Rc::new(RefCell::new(Password {
@@ -176,7 +175,7 @@ add t3 C 99 2022-12-14
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), }))),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Rc::new(RefCell::new(Password {
@@ -186,7 +185,7 @@ add t3 C 99 2022-12-14
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), }))),
Command::Noop Command::Noop
@@ -208,7 +207,7 @@ add t3 C 99 2022-12-14
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), }))),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Rc::new(RefCell::new(Password {
@@ -218,7 +217,7 @@ add t3 C 99 2022-12-14
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), }))),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Rc::new(RefCell::new(Password {
@@ -228,7 +227,7 @@ add t3 C 99 2022-12-14
length: None, length: None,
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2022, 12, 14).unwrap(), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), }))),
Command::Noop, Command::Noop,
@@ -248,7 +247,7 @@ add t3 C 99 2022-12-14
mode: Mode::Regular, mode: Mode::Regular,
length: None, length: None,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string())
}) })
); );
@@ -261,7 +260,7 @@ add t3 C 99 2022-12-14
mode: Mode::RegularUpcase, mode: Mode::RegularUpcase,
length: None, length: None,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string())
}) })
); );
@@ -274,7 +273,7 @@ add t3 C 99 2022-12-14
mode: Mode::RegularUpcase, mode: Mode::RegularUpcase,
length: None, length: None,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: None comment: None
}) })
); );
@@ -287,7 +286,7 @@ add t3 C 99 2022-12-14
mode: Mode::Regular, mode: Mode::Regular,
length: None, length: None,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string())
}) })
); );
@@ -300,7 +299,7 @@ add t3 C 99 2022-12-14
mode: Mode::NoSpace, mode: Mode::NoSpace,
length: None, length: None,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string())
}) })
); );
@@ -313,7 +312,7 @@ add t3 C 99 2022-12-14
mode: Mode::NoSpaceUpcase, mode: Mode::NoSpaceUpcase,
length: None, length: None,
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string()) comment: Some("xx.ableton@domain.info https://www.ableton.com".to_string())
}) })
); );
@@ -326,7 +325,7 @@ add t3 C 99 2022-12-14
mode: Mode::Regular, mode: Mode::Regular,
length: Some(20), length: Some(20),
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("a b c".to_string()) comment: Some("a b c".to_string())
}) })
); );
@@ -339,7 +338,7 @@ add t3 C 99 2022-12-14
mode: Mode::RegularUpcase, mode: Mode::RegularUpcase,
length: Some(20), length: Some(20),
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("a b c".to_string()) comment: Some("a b c".to_string())
}) })
); );
@@ -352,7 +351,7 @@ add t3 C 99 2022-12-14
mode: Mode::HexUpcase, mode: Mode::HexUpcase,
length: Some(20), length: Some(20),
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("a b c".to_string()) comment: Some("a b c".to_string())
}) })
); );
@@ -365,7 +364,7 @@ add t3 C 99 2022-12-14
mode: Mode::Base64Upcase, mode: Mode::Base64Upcase,
length: Some(20), length: Some(20),
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("a b c".to_string()) comment: Some("a b c".to_string())
}) })
); );
@@ -378,7 +377,7 @@ add t3 C 99 2022-12-14
mode: Mode::Decimal, mode: Mode::Decimal,
length: Some(20), length: Some(20),
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("a b c".to_string()) comment: Some("a b c".to_string())
}) })
); );
@@ -391,7 +390,7 @@ add t3 C 99 2022-12-14
mode: Mode::Decimal, mode: Mode::Decimal,
length: Some(20), length: Some(20),
seq: 98, seq: 98,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("a b c".to_string()) comment: Some("a b c".to_string())
}) })
); );
@@ -404,7 +403,7 @@ add t3 C 99 2022-12-14
mode: Mode::NoSpaceCamel, mode: Mode::NoSpaceCamel,
length: Some(20), length: Some(20),
seq: 98, seq: 98,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("a b c".to_string()) comment: Some("a b c".to_string())
}) })
); );
@@ -417,7 +416,7 @@ add t3 C 99 2022-12-14
mode: Mode::Decimal, mode: Mode::Decimal,
length: Some(20), length: Some(20),
seq: 99, seq: 99,
date: NaiveDate::from_ymd_opt(2020, 12, 09).unwrap(), date: Date::new(2020, 12, 09),
comment: Some("a b c".to_string()) comment: Some("a b c".to_string())
}) })
); );
+7 -8
View File
@@ -1,6 +1,6 @@
use crate::skey::SKey; use crate::skey::SKey;
use crate::structs::Mode; use crate::structs::Mode;
use chrono::naive::NaiveDate; use crate::utils::date::Date;
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
pub type Name = String; pub type Name = String;
@@ -10,7 +10,6 @@ pub type PasswordRef = Rc<RefCell<Password>>;
pub type Parent = Option<PasswordRef>; pub type Parent = Option<PasswordRef>;
pub type Length = Option<u32>; pub type Length = Option<u32>;
pub type Seq = u32; pub type Seq = u32;
pub type Date = NaiveDate;
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub struct Password { pub struct Password {
@@ -173,7 +172,7 @@ mod tests {
None, None,
Mode::Regular, Mode::Regular,
99, 99,
NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), Date::new(2022, 12, 3),
None, None,
))); )));
@@ -187,7 +186,7 @@ mod tests {
None, None,
Mode::Regular, Mode::Regular,
99, 99,
NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), Date::new(2022, 12, 3),
None, None,
))); )));
p2.borrow_mut().parent = Some(p1.clone()); p2.borrow_mut().parent = Some(p1.clone());
@@ -197,7 +196,7 @@ mod tests {
None, None,
Mode::Regular, Mode::Regular,
99, 99,
NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), Date::new(2022, 12, 3),
None, None,
))); )));
p3.borrow_mut().parent = Some(p2.clone()); p3.borrow_mut().parent = Some(p2.clone());
@@ -207,7 +206,7 @@ mod tests {
None, None,
Mode::Regular, Mode::Regular,
99, 99,
NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), Date::new(2022, 12, 3),
None, None,
))); )));
p4.borrow_mut().parent = Some(p3.clone()); p4.borrow_mut().parent = Some(p3.clone());
@@ -217,7 +216,7 @@ mod tests {
None, None,
Mode::Regular, Mode::Regular,
99, 99,
NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(), Date::new(2022, 12, 3),
None, None,
))); )));
p5.borrow_mut().parent = Some(p4.clone()); p5.borrow_mut().parent = Some(p4.clone());
@@ -230,7 +229,7 @@ mod tests {
#[test] #[test]
fn exec_encode_test() { fn exec_encode_test() {
let sec = "my secret"; let sec = "my secret";
let dat = NaiveDate::from_ymd_opt(2022, 12, 3).unwrap(); let dat = Date::new(2022, 12, 3);
let mut pwd = Password::new(None, "test1".to_string(), None, Mode::Regular, 99, dat, None); let mut pwd = Password::new(None, "test1".to_string(), None, Mode::Regular, 99, dat, None);
assert_eq!(pwd.encode(sec), "ross beau week held yoga anti"); assert_eq!(pwd.encode(sec), "ross beau week held yoga anti");
+5 -5
View File
@@ -1,15 +1,14 @@
use rpassword::prompt_password; use rpassword::prompt_password;
use rustyline::error::ReadlineError;
use rustyline::Editor;
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use crate::lk::LK; use crate::lk::LK;
use crate::parser::command_parser; use crate::parser::command_parser;
use crate::structs::{Command, LKErr, LKOut, HISTORY_FILE}; use crate::structs::{Command, LKErr, LKOut, HISTORY_FILE};
use crate::utils::editor::Editor;
#[derive(Debug)] #[derive(Debug)]
pub struct LKRead { pub struct LKRead {
pub rl: Editor<()>, pub rl: Editor,
pub prompt: String, pub prompt: String,
pub state: Rc<RefCell<LK>>, pub state: Rc<RefCell<LK>>,
pub cmd: String, pub cmd: String,
@@ -31,7 +30,7 @@ pub struct LKPrint {
} }
impl LKRead { impl LKRead {
pub fn new(rl: Editor<()>, prompt: String, state: Rc<RefCell<LK>>) -> Self { pub fn new(rl: Editor, prompt: String, state: Rc<RefCell<LK>>) -> Self {
Self { Self {
rl, rl,
prompt, prompt,
@@ -53,7 +52,7 @@ impl LKRead {
} }
self.cmd = match self.rl.readline(&*self.prompt) { self.cmd = match self.rl.readline(&*self.prompt) {
Ok(str) => str, Ok(str) => str,
Err(ReadlineError::Eof | ReadlineError::Interrupted) => "quit".to_string(), Err(LKErr::EOF) => "quit".to_string(),
Err(err) => { Err(err) => {
return LKEval::new( return LKEval::new(
Command::Error(LKErr::ReadError(err.to_string())), Command::Error(LKErr::ReadError(err.to_string())),
@@ -128,6 +127,7 @@ impl<'a> LKEval<'a> {
Command::Error(error) => match error { Command::Error(error) => match error {
LKErr::ParseError(e) => out.e(e.to_string()), LKErr::ParseError(e) => out.e(e.to_string()),
LKErr::ReadError(e) => out.e(e.to_string()), LKErr::ReadError(e) => out.e(e.to_string()),
LKErr::EOF => out.e("error: end of file".to_string()),
LKErr::Error(e) => out.e(format!("error: {}", e.to_string())), LKErr::Error(e) => out.e(format!("error: {}", e.to_string())),
}, },
} }
View File
+9 -7
View File
@@ -1,7 +1,5 @@
use crate::password::{Comment, Name, PasswordRef}; use crate::password::{Comment, Name, PasswordRef};
use home::home_dir;
use rpassword::prompt_password; use rpassword::prompt_password;
use rustyline::Editor;
use std::fmt; use std::fmt;
use std::path::Path; use std::path::Path;
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
@@ -9,12 +7,14 @@ use std::{cell::RefCell, rc::Rc};
use crate::lk::LK; use crate::lk::LK;
use crate::parser::command_parser; use crate::parser::command_parser;
use crate::repl::{LKEval, LKRead}; use crate::repl::{LKEval, LKRead};
use crate::utils::home;
use crate::utils::editor::Editor;
lazy_static! { lazy_static! {
pub static ref HISTORY_FILE: Box<Path> = { pub static ref HISTORY_FILE: Box<Path> = {
match std::env::var("HEL_HISTORY") { match std::env::var("HEL_HISTORY") {
Ok(v) => Path::new(shellexpand::full(&v).unwrap().into_owned().as_str()).to_path_buf().into_boxed_path(), Ok(v) => Path::new(shellexpand::full(&v).unwrap().into_owned().as_str()).to_path_buf().into_boxed_path(),
_ => home_dir().unwrap().join(".hel_history").into_boxed_path(), _ => home::dir().join(".hel_history").into_boxed_path(),
} }
}; };
pub static ref PROMPT_SETTING: String = { pub static ref PROMPT_SETTING: String = {
@@ -26,19 +26,19 @@ lazy_static! {
pub static ref INIT_FILE: Box<Path> = { pub static ref INIT_FILE: Box<Path> = {
match std::env::var("HEL_INIT") { match std::env::var("HEL_INIT") {
Ok(v) => Path::new(shellexpand::full(&v).unwrap().into_owned().as_str()).to_path_buf().into_boxed_path(), Ok(v) => Path::new(shellexpand::full(&v).unwrap().into_owned().as_str()).to_path_buf().into_boxed_path(),
_ => home_dir().unwrap().join(".helrc").into_boxed_path(), _ => home::dir().join(".helrc").into_boxed_path(),
} }
}; };
pub static ref CORRECT_FILE: Box<Path> = { pub static ref CORRECT_FILE: Box<Path> = {
match std::env::var("HEL_CORRECT") { match std::env::var("HEL_CORRECT") {
Ok(v) => Path::new(shellexpand::full(&v).unwrap().into_owned().as_str()).to_path_buf().into_boxed_path(), Ok(v) => Path::new(shellexpand::full(&v).unwrap().into_owned().as_str()).to_path_buf().into_boxed_path(),
_ => home_dir().unwrap().join(".hel_correct").into_boxed_path(), _ => home::dir().join(".hel_correct").into_boxed_path(),
} }
}; };
pub static ref DUMP_FILE: Box<Path> = { pub static ref DUMP_FILE: Box<Path> = {
match std::env::var("HEL_DUMP") { match std::env::var("HEL_DUMP") {
Ok(v) => Path::new(shellexpand::full(&v).unwrap().into_owned().as_str()).to_path_buf().into_boxed_path(), Ok(v) => Path::new(shellexpand::full(&v).unwrap().into_owned().as_str()).to_path_buf().into_boxed_path(),
_ => home_dir().unwrap().join(".hel_dump").into_boxed_path(), _ => home::dir().join(".hel_dump").into_boxed_path(),
} }
}; };
} }
@@ -47,6 +47,8 @@ lazy_static! {
pub enum LKErr<'a> { pub enum LKErr<'a> {
#[error("Error: {0}")] #[error("Error: {0}")]
Error(&'a str), Error(&'a str),
#[error("Error: end of file")]
EOF,
#[error("Failed to read the line: {0}")] #[error("Failed to read the line: {0}")]
ReadError(String), ReadError(String),
#[error("Failed to parse: {0}")] #[error("Failed to parse: {0}")]
@@ -288,7 +290,7 @@ pub fn init() -> Option<LKRead> {
.print(); .print();
} }
} }
Some(LKRead::new(Editor::<()>::new().unwrap(), PROMPT_SETTING.to_string(), lk.clone())) Some(LKRead::new(Editor::new(), PROMPT_SETTING.to_string(), lk.clone()))
} }
#[cfg(test)] #[cfg(test)]
+179
View File
@@ -0,0 +1,179 @@
use shlex::split;
use std::env;
use std::ffi::OsString;
use std::io;
use std::io::{Read, Write};
use std::process::{Command, Stdio};
#[cfg(not(wasm))]
pub mod date {
use chrono::naive::NaiveDate;
use chrono::Local;
#[derive(PartialEq, Debug, Clone)]
pub struct Date {
date: NaiveDate
}
impl Date {
pub fn new(year: i32, month: u32, day: u32) -> Self {
Self { date: NaiveDate::from_ymd_opt(year, month, day).unwrap() }
}
pub fn try_new(year: i32, month: u32, day: u32) -> Result<Self, &'static str> {
match NaiveDate::from_ymd_opt(year, month, day) {
Some(d) => Ok(Self { date: d }),
None => Err("error: failed to parse the date"),
}
}
pub fn now() -> Self {
Self { date: Local::now().naive_local().date() }
}
pub fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.date.cmp(&other.date)
}
}
impl std::fmt::Display for Date {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.date.to_string())
}
}
}
#[cfg(not(wasm))]
pub mod rnd {
use rand::{thread_rng, Rng};
pub fn range(start: u32, end: u32) -> u32 {
thread_rng().gen_range(start..end)
}
}
#[cfg(unix)]
pub mod home {
use home::home_dir;
use std::path::PathBuf;
pub fn dir() -> PathBuf {
home_dir().unwrap()
}
}
#[cfg(unix)]
pub mod editor {
use crate::structs::LKErr;
use rustyline::error::ReadlineError;
#[derive(Debug)]
pub struct Editor {
editor: rustyline::Editor<()>,
}
impl Editor {
pub fn new() -> Self {
Self { editor: rustyline::Editor::<()>::new().unwrap() }
}
pub fn clear_history(&mut self) {
self.editor.clear_history();
}
pub fn add_history_entry(&mut self, entry: &str) {
self.editor.add_history_entry(entry);
}
pub fn load_history<'a>(&mut self, fname: &str) -> Result<(), LKErr<'a>> {
match self.editor.load_history(&fname) {
Ok(_) => Ok(()),
Err(_) => Err(LKErr::Error("failed to read history file")),
}
}
pub fn save_history<'a>(&mut self, fname: &str) -> Result<(), LKErr<'a>> {
match self.editor.save_history(&fname) {
Ok(_) => Ok(()),
Err(ReadlineError::Eof | ReadlineError::Interrupted) => Err(LKErr::EOF),
Err(_) => Err(LKErr::Error("failed to write history file")),
}
}
pub fn readline<'a>(&mut self, prompt: &str) -> Result<String, LKErr<'a>> {
match self.editor.readline(&prompt) {
Ok(line) => Ok(line),
Err(_) => Err(LKErr::Error("failed to read from input")),
}
}
}
}
pub fn call_cmd_with_input(cmd: &str, args: &Vec<String>, input: &str) -> io::Result<String> {
let mut cmd = Command::new(cmd).args(args).stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?;
let mut stdin = cmd.stdin.take().unwrap();
let stdout = cmd.stdout.as_mut().unwrap();
let in_data = input.to_string();
let write_handle = std::thread::spawn(move || stdin.write_all(in_data.as_bytes()));
let mut output = Vec::new();
stdout.read_to_end(&mut output)?;
match write_handle.join() {
Ok(_) => (),
Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "Failed to run command")),
}
match String::from_utf8(output) {
Ok(x) => Ok(x),
Err(err) => Err(io::Error::new(io::ErrorKind::InvalidData, err.utf8_error())),
}
}
pub fn get_cmd_args_from_command(command: &str) -> io::Result<(String, Vec<String>)> {
let args = match split(command) {
Some(c) => c,
None => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("Failed to parse the command: {:?}", command),
))
}
};
Ok((shellexpand::full(&args[0]).unwrap().into_owned(), args[1..].to_vec()))
}
pub fn get_copy_command_from_env() -> (String, Vec<String>) {
let cmd_os_str = env::var_os("HEL_PB").unwrap_or_else(|| match env::consts::OS {
_ if env::var("TMUX").is_ok() => OsString::from("tmux load-buffer -"),
"macos" => OsString::from("pbcopy"),
"linux" => OsString::from("xclip"),
_ => OsString::from("cat"),
});
get_cmd_args_from_command(&cmd_os_str.to_string_lossy()).unwrap_or_else(|_| ("cat".to_string(), vec![]))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cmd_exec_test() {
assert_eq!(call_cmd_with_input("true", &vec![], "").unwrap(), "".to_string());
assert_eq!(call_cmd_with_input("cat", &vec![], "ok").unwrap(), "ok".to_string());
assert_eq!(
call_cmd_with_input(
"cat",
&vec![],
r###"line 1
line 2
line 3
line 4"###
)
.unwrap(),
"line 1\nline 2\nline 3\nline 4".to_string()
);
assert_ne!(call_cmd_with_input("cat", &vec![], "notok").unwrap(), "ok".to_string());
assert_eq!(
call_cmd_with_input("echo", &vec!["-n".to_string(), "test is ok".to_string()], "").unwrap(),
"test is ok".to_string()
);
}
}
+14
View File
@@ -0,0 +1,14 @@
[package]
name = "helcli"
version = "0.1.0"
authors = ["ok2"]
edition = "2021"
[[bin]]
name = "hel"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hel = { version = "0.1.0", path = "../hel" }
rustyline = "10.0.0"
+12
View File
@@ -0,0 +1,12 @@
extern crate hel;
use hel::structs::init;
pub fn main() {
let mut lkread = match init() { Some(r) => r, None => { return; } };
while lkread.read().eval().print() {
lkread.refresh();
}
lkread.quit();
}
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "helwasm"
version = "0.1.0"
authors = ["ok2"]
edition = "2021"
[target.'cfg(wasm32)']
[lib]
name = "helwasm"
path = "src/lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hel = { version = "0.1.0", path = "../hel" }
wasm-bindgen = "0.2.83"
+8
View File
@@ -0,0 +1,8 @@
extern crate hel;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b + 1
}
-26
View File
@@ -1,26 +0,0 @@
#![recursion_limit = "1024"]
#[macro_use]
extern crate lazy_static;
#[allow(unused_imports)]
#[macro_use(defer)]
extern crate scopeguard;
mod commands;
mod lk;
mod parser;
mod password;
mod repl;
mod skey;
mod structs;
mod utils;
use crate::structs::init;
pub fn main() {
let mut lkread = match init() { Some(r) => r, None => { return; } };
while lkread.read().eval().print() {
lkread.refresh();
}
lkread.quit();
}
-75
View File
@@ -1,75 +0,0 @@
use shlex::split;
use std::env;
use std::ffi::OsString;
use std::io;
use std::io::{Read, Write};
use std::process::{Command, Stdio};
pub fn call_cmd_with_input(cmd: &str, args: &Vec<String>, input: &str) -> io::Result<String> {
let mut cmd = Command::new(cmd).args(args).stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?;
let mut stdin = cmd.stdin.take().unwrap();
let stdout = cmd.stdout.as_mut().unwrap();
let in_data = input.to_string();
let write_handle = std::thread::spawn(move || stdin.write_all(in_data.as_bytes()));
let mut output = Vec::new();
stdout.read_to_end(&mut output)?;
match write_handle.join() {
Ok(_) => (),
Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "Failed to run command")),
}
match String::from_utf8(output) {
Ok(x) => Ok(x),
Err(err) => Err(io::Error::new(io::ErrorKind::InvalidData, err.utf8_error())),
}
}
pub fn get_cmd_args_from_command(command: &str) -> io::Result<(String, Vec<String>)> {
let args = match split(command) {
Some(c) => c,
None => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("Failed to parse the command: {:?}", command),
))
}
};
Ok((shellexpand::full(&args[0]).unwrap().into_owned(), args[1..].to_vec()))
}
pub fn get_copy_command_from_env() -> (String, Vec<String>) {
let cmd_os_str = env::var_os("HEL_PB").unwrap_or_else(|| match env::consts::OS {
_ if env::var("TMUX").is_ok() => OsString::from("tmux load-buffer -"),
"macos" => OsString::from("pbcopy"),
"linux" => OsString::from("xclip"),
_ => OsString::from("cat"),
});
get_cmd_args_from_command(&cmd_os_str.to_string_lossy()).unwrap_or_else(|_| ("cat".to_string(), vec![]))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cmd_exec_test() {
assert_eq!(call_cmd_with_input("true", &vec![], "").unwrap(), "".to_string());
assert_eq!(call_cmd_with_input("cat", &vec![], "ok").unwrap(), "ok".to_string());
assert_eq!(
call_cmd_with_input(
"cat",
&vec![],
r###"line 1
line 2
line 3
line 4"###
)
.unwrap(),
"line 1\nline 2\nline 3\nline 4".to_string()
);
assert_ne!(call_cmd_with_input("cat", &vec![], "notok").unwrap(), "ok".to_string());
assert_eq!(
call_cmd_with_input("echo", &vec!["-n".to_string(), "test is ok".to_string()], "").unwrap(),
"test is ok".to_string()
);
}
}