diff --git a/src/cmd/echo.rs b/src/cmd/echo.rs new file mode 100644 index 0000000..627d50f --- /dev/null +++ b/src/cmd/echo.rs @@ -0,0 +1,17 @@ +use crate::command::Command; + +pub fn init() -> Command { + Command::init( + "echo", + vec![], + Box::new(|args, _| { + let msg = &args[1..] + .iter() + .map(|s| s.to_owned()) + .intersperse(" ".to_string()) + .collect::(); + println!("{msg}"); + 0 + }), + ) +} diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs new file mode 100644 index 0000000..6f712ae --- /dev/null +++ b/src/cmd/mod.rs @@ -0,0 +1,2 @@ +pub mod echo; +pub mod random; diff --git a/src/cmd/random.rs b/src/cmd/random.rs new file mode 100644 index 0000000..d311c79 --- /dev/null +++ b/src/cmd/random.rs @@ -0,0 +1,31 @@ +use crate::command::Command; + +pub fn init() -> Command { + Command::init( + "random", + vec![ + Command::init( + "number", + vec![], + Box::new(|_, _| { + // how do you know it's not random? + println!("8"); + 0 + }), + ), + Command::init( + "string", + vec![], + Box::new(|_, _| { + // how do you know it's not random? + println!("hello world"); + 0 + }), + ), + ], + Box::new(|args, env| { + println!("args: {:?} env: {:?}", args, env); + 0 + }), + ) +} diff --git a/src/command.rs b/src/command.rs index b534e26..7530681 100644 --- a/src/command.rs +++ b/src/command.rs @@ -8,11 +8,23 @@ use std::{ use crate::SPECIAL_CHAR; type InnerEnv = HashMap; -pub struct Env { +pub struct CmdEnv { inner: InnerEnv, } -impl Env { +impl std::fmt::Debug for CmdEnv { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut stu = f.debug_struct("CmdEnv"); + + for (k,v) in self.inner.iter() { + stu.field(k, v); + } + stu + .finish() + } +} + +impl CmdEnv { pub fn new() -> Self { Self { inner: HashMap::new(), @@ -46,7 +58,8 @@ impl Env { } pub type Args<'a, 'b> = &'b [String]; -trait Run = Fn(Args, &mut Env) -> i32; +// A function that takes args, the env, and returns a status code +trait Run = Fn(Args, &mut CmdEnv) -> i32; type Cmd = Box; pub struct Command { @@ -56,7 +69,7 @@ pub struct Command { } impl Command { - fn init(name: T, sub_commands: Vec, f: Cmd) -> Self + pub fn init(name: T, sub_commands: Vec, f: Cmd) -> Self where T: ToString, { @@ -67,7 +80,7 @@ impl Command { } } - pub fn call(&self, words: Args, env: &mut Env) { + pub fn call(&self, words: Args, env: &mut CmdEnv) { let x = &self.cmd; let exit_code = x(words, env); env.set("?", &exit_code.to_string()); @@ -110,7 +123,7 @@ impl Command { fn load_from(path: &str) -> Vec { let path = Path::new(path); if let Ok(res) = fs::read_dir(path) { - // load all the programs from /bin + // load all the programs from let bin = res.fold(Vec::new(), |mut v, contents| { if let Ok(cmd) = contents { if let Ok(t) = cmd.file_type() { @@ -119,10 +132,8 @@ impl Command { let cmd = Command::init( cmd.file_name().into_string().unwrap(), vec![], - Box::new(move |args: Args, env: &mut Env| { - let name = cmd.path().to_str().unwrap().to_owned(); - let out = process::Command::new(name) - .args(&args[1..]) + Box::new(move |args: Args, env: &mut CmdEnv| { + let name = cmd.path().to_str().unwrap().to_owned(); let out = process::Command::new(name) .args(&args[1..]) .envs(env.as_env()) .output() .expect("Failed to call external program"); @@ -149,7 +160,7 @@ impl Command { Vec::new() } - pub fn all_commands(env: &Env) -> Vec { + pub fn all_commands(env: &CmdEnv) -> Vec { // load custom programs let mut commands = vec![ Command::init( @@ -159,46 +170,8 @@ impl Command { std::process::exit(0); }), ), - Command::init( - "echo", - vec![], - Box::new(|args, _| { - let msg = &args[1..] - .iter() - .map(|s| s.to_owned()) - .intersperse(" ".to_string()) - .collect::(); - println!("{msg}"); - 0 - }), - ), - Command::init( - "random", - vec![ - Command::init( - "number", - vec![], - Box::new(|_, _| { - // how do you know it's not random? - println!("8"); - 0 - }), - ), - Command::init( - "string", - vec![], - Box::new(|_, _| { - // how do you know it's not random? - println!("hello world"); - 0 - }), - ), - ], - Box::new(|args, _| { - println!("random's debug: {:?}", args); - 0 - }), - ), + crate::cmd::echo::init(), + crate::cmd::random::init(), ]; // $PATH diff --git a/src/main.rs b/src/main.rs index 9ff7526..b16eb4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,10 @@ #![feature(iter_intersperse)] #![feature(trait_alias)] use std::io::{BufRead, Write}; -use command::{Command, Env, Args}; +use command::{Command, CmdEnv, Args}; mod command; +mod cmd; pub static SPECIAL_CHAR: char = '$'; @@ -14,9 +15,10 @@ fn main() { let stdout = std::io::stdout(); let mut out_lock = stdout.lock(); - let mut env= Env::new(); - env.set("HOME", "/a/fake/dir"); + let mut env= CmdEnv::new(); + env.set("HOME", "/tmp/fake/dir"); env.set("?", "0"); + // env.set("PATH", "/bin/"); let commands = &Command::all_commands(&env); println!("Loaded {} commands", commands.len()); @@ -78,7 +80,7 @@ fn main() { } } -fn parse_lang(tokens: Args, env: &mut Env) { +fn parse_lang(tokens: Args, env: &mut CmdEnv) { if let Some(first) = tokens.first() { if let Some((var, val)) = first.split_once('=') { let var = var.replace(SPECIAL_CHAR, ""); @@ -100,7 +102,7 @@ fn parse_lang(tokens: Args, env: &mut Env) { }; env.set(&var, &val); } else { - println!("first token is not a command but also doesn't include '='"); + println!("first token is not a command but also isn't setting a variable (=)"); } } }