Restructuring

This commit is contained in:
Daniel Kluge 2024-01-03 12:56:40 +01:00
parent 2d9db49fef
commit c0fe46cf34
4 changed files with 224 additions and 227 deletions

View File

@ -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);
} }

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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);
} }