Restructuring
This commit is contained in:
parent
2d9db49fef
commit
c0fe46cf34
@ -1,11 +1,9 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::{Command, types::Content};
|
use super::{Command, types::Content};
|
||||||
|
|
||||||
// TODO: Remove this
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
extern "C" {
|
extern {
|
||||||
#[wasm_bindgen(js_namespace = console)]
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
fn log(s: &str);
|
fn log(s: &str);
|
||||||
}
|
}
|
@ -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<Rc<Flag>>,
|
|
||||||
function: fn(&mut Console, Vec<String>, Vec<Rc<Flag>>) -> Result<Option<String>, &'static str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command {
|
|
||||||
pub fn new(name: String, description: String, flags: Vec<Rc<Flag>>, function: fn(&mut Console, Vec<String>, Vec<Rc<Flag>>) -> Result<Option<String>, &'static str>) -> Command {
|
|
||||||
Command {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
flags,
|
|
||||||
function,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_flags(&self, args: Vec<String>) -> (Vec<Rc<Flag>>, Vec<String>) {
|
|
||||||
let mut flags: Vec<Rc<Flag>> = 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<String>) -> Result<Option<String>, &'static str> {
|
|
||||||
let (flags, args) = self.parse_flags(args.clone());
|
|
||||||
(self.function)(console, args, flags)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct Console {
|
|
||||||
root: Rc<RefCell<Directory>>,
|
|
||||||
pwd: RefCell<Vec<Rc<RefCell<Directory>>>>,
|
|
||||||
last_commands: Vec<String>,
|
|
||||||
available_commands: Vec<Rc<Command>>,
|
|
||||||
output: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Console {
|
|
||||||
fn get_current_dir(&self) -> Rc<RefCell<Directory>> {
|
|
||||||
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<usize>) -> 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<usize>) -> Result<Rc<RefCell<Directory>>, &'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<String> {
|
|
||||||
let mut args: Vec<String> = 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<String> {
|
|
||||||
self.output.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_last_commands(&self) -> Vec<String> {
|
|
||||||
self.last_commands.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute(&mut self, command: String) -> Option<String> {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
222
src/lib.rs
222
src/lib.rs
@ -1 +1,221 @@
|
|||||||
mod console;
|
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<Rc<Flag>>,
|
||||||
|
function: fn(&mut Console, Vec<String>, Vec<Rc<Flag>>) -> Result<Option<String>, &'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
pub fn new(name: String, description: String, flags: Vec<Rc<Flag>>, function: fn(&mut Console, Vec<String>, Vec<Rc<Flag>>) -> Result<Option<String>, &'static str>) -> Command {
|
||||||
|
Command {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
flags,
|
||||||
|
function,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_flags(&self, args: Vec<String>) -> (Vec<Rc<Flag>>, Vec<String>) {
|
||||||
|
let mut flags: Vec<Rc<Flag>> = 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<String>) -> Result<Option<String>, &'static str> {
|
||||||
|
let (flags, args) = self.parse_flags(args.clone());
|
||||||
|
(self.function)(console, args, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct Console {
|
||||||
|
root: Rc<RefCell<Directory>>,
|
||||||
|
pwd: RefCell<Vec<Rc<RefCell<Directory>>>>,
|
||||||
|
last_commands: Vec<String>,
|
||||||
|
available_commands: Vec<Rc<Command>>,
|
||||||
|
output: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Console {
|
||||||
|
fn get_current_dir(&self) -> Rc<RefCell<Directory>> {
|
||||||
|
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<usize>) -> 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<usize>) -> Result<Rc<RefCell<Directory>>, &'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<String> {
|
||||||
|
let mut args: Vec<String> = 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<String> {
|
||||||
|
self.output.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_last_commands(&self) -> Vec<String> {
|
||||||
|
self.last_commands.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(&mut self, command: String) -> Option<String> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
// TODO: Remove this
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
extern "C" {
|
extern {
|
||||||
#[wasm_bindgen(js_namespace = console)]
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
fn log(s: &str);
|
fn log(s: &str);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user