diff --git a/src/console/commands.rs b/src/commands.rs similarity index 99% rename from src/console/commands.rs rename to src/commands.rs index 2d0556c..97f61e9 100644 --- a/src/console/commands.rs +++ b/src/commands.rs @@ -1,11 +1,9 @@ use std::rc::Rc; - use super::{Command, types::Content}; -// TODO: Remove this use wasm_bindgen::prelude::*; #[wasm_bindgen] -extern "C" { +extern { #[wasm_bindgen(js_namespace = console)] fn log(s: &str); } diff --git a/src/console/mod.rs b/src/console/mod.rs deleted file mode 100644 index cb89b3a..0000000 --- a/src/console/mod.rs +++ /dev/null @@ -1,220 +0,0 @@ -extern crate console_error_panic_hook; -mod types; -mod commands; -use std::{cell::RefCell, rc::Rc}; - -use types::*; -use commands::commands; -use wasm_bindgen::prelude::*; - -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} - -pub struct Flag { - pub long: String, - pub short: String, - pub description: String, -} - -#[allow(unused)] -impl Flag { - pub fn new(long: String, short: String, description: String) -> Flag { - Flag { - long, - short, - description, - } - } -} - -pub struct Command { - pub name: String, - pub description: String, - pub flags: Vec>, - function: fn(&mut Console, Vec, Vec>) -> Result, &'static str>, -} - -impl Command { - pub fn new(name: String, description: String, flags: Vec>, function: fn(&mut Console, Vec, Vec>) -> Result, &'static str>) -> Command { - Command { - name, - description, - flags, - function, - } - } - - fn parse_flags(&self, args: Vec) -> (Vec>, Vec) { - let mut flags: Vec> = Vec::new(); - let mut other = Vec::new(); - - for arg in args { - if arg.starts_with("--") { - let f = match self.flags.iter().find(|f| arg[2..] == f.long) { - Some(f) => Rc::clone(f), - None => continue, - }; - flags.push(f); - } else if arg.starts_with("-") { - let f = match self.flags.iter().find(|f| arg[1..] == f.short) { - Some(f) => Rc::clone(f), - None => continue, - }; - flags.push(f); - } else { - other.push(arg); - } - } - - (flags, other) - } - - pub fn execute(&self, console: &mut Console, args: Vec) -> Result, &'static str> { - let (flags, args) = self.parse_flags(args.clone()); - (self.function)(console, args, flags) - } -} - -#[wasm_bindgen] -pub struct Console { - root: Rc>, - pwd: RefCell>>>, - last_commands: Vec, - available_commands: Vec>, - output: Vec, -} - -impl Console { - fn get_current_dir(&self) -> Rc> { - match self.pwd.borrow().last() { - Some(dir) => Rc::clone(dir), - None => Rc::clone(&self.root), - } - } - - fn cd(&mut self, path: String, skip_last_n: Option) -> Result<(), &'static str> { - let segments = PathSegment::parse_path_segment(path); - let mut current = self.get_current_dir(); - - let mut index = 0; - let break_index = match skip_last_n { - Some(n) => segments.len() - n as usize, - None => segments.len(), - }; - - for segment in segments { - if index >= break_index { - break; - } else { - index += 1; - } - - match segment { - PathSegment::Root => { - self.pwd.borrow_mut().clear(); - continue; - }, - PathSegment::This => continue, - PathSegment::Parent => { - if self.pwd.borrow().len() == 0 { - return Err("Cannot go above root directory"); - } - self.pwd.borrow_mut().pop(); - continue; - }, - PathSegment::SubDirectory(name) => { - let dir = match current.borrow().get_dir(name) { - Some(dir) => dir, - None => return Err("Directory does not exist"), - }; - self.pwd.borrow_mut().push(dir); - }, - } - - current = self.get_current_dir(); - } - - Ok(()) - } - - // Function to get a directory from a path - // the PWD should be unchanged after this function - fn virtual_cd(&mut self, path: String, skip_last_n: Option) -> Result>, &'static str> { - let pwd = self.pwd.borrow().clone(); - - match self.cd(path, skip_last_n) { - Ok(_) => (), - Err(e) => return Err(e), - }; - let result = self.get_current_dir(); - self.pwd.replace(pwd); - - Ok(result) - } - - fn execute_inner(&mut self, command: String) -> Option { - let mut args: Vec = command.split(" ").map(|s| s.to_string()).collect(); - - let command = match args.first() { - Some(command) => command, - None => return Some("No command entered".to_string()), - }; - - let command = match self.available_commands.iter().find(|c| c.name == *command) { - Some(command) => command.clone(), - None => return Some(format!("Command {} not found", command)), - }; - - args.remove(0); - - let result = command.execute(self, args); - - match result { - Ok(result) => { - self.last_commands.push(command.name.clone()); - result - }, - Err(e) => Some(e.to_string()), - } - } -} - -#[wasm_bindgen] -impl Console { - pub fn new() -> Console { - console_error_panic_hook::set_once(); - - let root = Rc::new(RefCell::new(Directory::new("".to_string(), "".to_string()))); - - let console = Console { - root, - pwd: RefCell::new(Vec::new()), - output: Vec::new(), - last_commands: Vec::new(), - available_commands: commands(), - }; - - console - } - - pub fn get_output(&self) -> Vec { - self.output.clone() - } - - pub fn get_last_commands(&self) -> Vec { - self.last_commands.clone() - } - - pub fn execute(&mut self, command: String) -> Option { - self.output.push(format!("$ {}", command)); - self.last_commands.push(command.clone()); - let result = self.execute_inner(command); - if result.is_some() { - self.output.push(result.clone().unwrap()); - } - result - } -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b69c7a9..6a4bb2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,221 @@ -mod console; \ No newline at end of file +extern crate console_error_panic_hook; +mod types; +mod commands; + +use std::{cell::RefCell, rc::Rc}; +use types::*; +use commands::commands; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +pub struct Flag { + pub long: String, + pub short: String, + pub description: String, +} + +#[allow(unused)] +impl Flag { + pub fn new(long: String, short: String, description: String) -> Flag { + Flag { + long, + short, + description, + } + } +} + +pub struct Command { + pub name: String, + pub description: String, + pub flags: Vec>, + function: fn(&mut Console, Vec, Vec>) -> Result, &'static str>, +} + +impl Command { + pub fn new(name: String, description: String, flags: Vec>, function: fn(&mut Console, Vec, Vec>) -> Result, &'static str>) -> Command { + Command { + name, + description, + flags, + function, + } + } + + fn parse_flags(&self, args: Vec) -> (Vec>, Vec) { + let mut flags: Vec> = Vec::new(); + let mut other = Vec::new(); + + for arg in args { + if arg.starts_with("--") { + let f = match self.flags.iter().find(|f| arg[2..] == f.long) { + Some(f) => Rc::clone(f), + None => continue, + }; + flags.push(f); + } else if arg.starts_with("-") { + let f = match self.flags.iter().find(|f| arg[1..] == f.short) { + Some(f) => Rc::clone(f), + None => continue, + }; + flags.push(f); + } else { + other.push(arg); + } + } + + (flags, other) + } + + pub fn execute(&self, console: &mut Console, args: Vec) -> Result, &'static str> { + let (flags, args) = self.parse_flags(args.clone()); + (self.function)(console, args, flags) + } +} + +#[wasm_bindgen] +pub struct Console { + root: Rc>, + pwd: RefCell>>>, + last_commands: Vec, + available_commands: Vec>, + output: Vec, +} + +impl Console { + fn get_current_dir(&self) -> Rc> { + match self.pwd.borrow().last() { + Some(dir) => Rc::clone(dir), + None => Rc::clone(&self.root), + } + } + + fn cd(&mut self, path: String, skip_last_n: Option) -> Result<(), &'static str> { + let segments = PathSegment::parse_path_segment(path); + let mut current = self.get_current_dir(); + + let mut index = 0; + let break_index = match skip_last_n { + Some(n) => segments.len() - n as usize, + None => segments.len(), + }; + + for segment in segments { + if index >= break_index { + break; + } else { + index += 1; + } + + match segment { + PathSegment::Root => { + self.pwd.borrow_mut().clear(); + continue; + }, + PathSegment::This => continue, + PathSegment::Parent => { + if self.pwd.borrow().len() == 0 { + return Err("Cannot go above root directory"); + } + self.pwd.borrow_mut().pop(); + continue; + }, + PathSegment::SubDirectory(name) => { + let dir = match current.borrow().get_dir(name) { + Some(dir) => dir, + None => return Err("Directory does not exist"), + }; + self.pwd.borrow_mut().push(dir); + }, + } + + current = self.get_current_dir(); + } + + Ok(()) + } + + // Function to get a directory from a path + // the PWD should be unchanged after this function + fn virtual_cd(&mut self, path: String, skip_last_n: Option) -> Result>, &'static str> { + let pwd = self.pwd.borrow().clone(); + + match self.cd(path, skip_last_n) { + Ok(_) => (), + Err(e) => return Err(e), + }; + let result = self.get_current_dir(); + self.pwd.replace(pwd); + + Ok(result) + } + + fn execute_inner(&mut self, command: String) -> Option { + let mut args: Vec = command.split(" ").map(|s| s.to_string()).collect(); + + let command = match args.first() { + Some(command) => command, + None => return Some("No command entered".to_string()), + }; + + let command = match self.available_commands.iter().find(|c| c.name == *command) { + Some(command) => command.clone(), + None => return Some(format!("Command {} not found", command)), + }; + + args.remove(0); + + let result = command.execute(self, args); + + match result { + Ok(result) => { + self.last_commands.push(command.name.clone()); + result + }, + Err(e) => Some(e.to_string()), + } + } +} + +#[wasm_bindgen] +impl Console { + pub fn new() -> Console { + // TODO remove in release + console_error_panic_hook::set_once(); + + let root = Rc::new(RefCell::new(Directory::new("".to_string(), "".to_string()))); + + let console = Console { + root, + pwd: RefCell::new(Vec::new()), + output: Vec::new(), + last_commands: Vec::new(), + available_commands: commands(), + }; + + console + } + + pub fn get_output(&self) -> Vec { + self.output.clone() + } + + pub fn get_last_commands(&self) -> Vec { + self.last_commands.clone() + } + + pub fn execute(&mut self, command: String) -> Option { + self.output.push(format!("$ {}", command)); + self.last_commands.push(command.clone()); + let result = self.execute_inner(command); + if result.is_some() { + self.output.push(result.clone().unwrap()); + } + result + } +} \ No newline at end of file diff --git a/src/console/types.rs b/src/types.rs similarity index 99% rename from src/console/types.rs rename to src/types.rs index 09e5b8b..48e6de9 100644 --- a/src/console/types.rs +++ b/src/types.rs @@ -1,9 +1,8 @@ use std::{cell::RefCell, rc::Rc}; - -// TODO: Remove this use wasm_bindgen::prelude::*; + #[wasm_bindgen] -extern "C" { +extern { #[wasm_bindgen(js_namespace = console)] fn log(s: &str); }