zenyx-engine-telemetry/engine/src/core/repl/commands.rs

321 lines
8.7 KiB
Rust
Raw Normal View History

use std::{fs, path::PathBuf, str::FromStr};
2025-01-11 15:28:01 -05:00
use parking_lot::RwLock;
use regex::Regex;
2024-12-01 16:02:06 -05:00
use super::{handler::Command, input::tokenize};
use crate::core::repl::handler::COMMAND_MANAGER;
2025-04-03 01:37:53 -04:00
use crate::error::{ZenyxError, ZenyxErrorKind};
#[derive(Default)]
pub struct HelpCommand;
impl Command for HelpCommand {
fn execute(&self, _args: Option<Vec<String>>) -> Result<(), ZenyxError> {
let manager = COMMAND_MANAGER.read();
println!("Available commands:\n");
for (_, command) in manager.get_commands() {
println!(
"Command: {}\n\tDescription: {}\n\tParameters: {}\n\tHelp: {}\n",
command.get_name().to_lowercase(),
command.get_description(),
command.get_params(),
command.get_help()
);
}
if !manager.aliases.is_empty() {
println!("Aliases:");
for (alias, command) in &manager.aliases {
println!("\t{} -> {}", alias, command);
}
}
Ok(())
2025-03-22 21:58:27 -04:00
}
fn undo(&self) {}
fn redo(&self) {}
fn get_description(&self) -> String {
String::from("help")
}
fn get_help(&self) -> String {
String::from("Displays a list of available commands and their descriptions.")
}
fn get_params(&self) -> String {
String::from("No parameters required.")
}
2024-12-05 11:00:08 -05:00
fn get_name(&self) -> String {
String::from("Help")
}
2024-12-01 16:02:06 -05:00
}
#[derive(Default)]
pub struct ClearCommand;
impl Command for ClearCommand {
fn execute(&self, _args: Option<Vec<String>>) -> Result<(), ZenyxError> {
println!("Clearing screen..., running command");
let _result = if cfg!(target_os = "windows") {
std::process::Command::new("cmd")
.args(["/c", "cls"])
.spawn()
} else {
std::process::Command::new("clear").spawn()
};
Ok(())
}
fn undo(&self) {}
2024-12-01 16:02:06 -05:00
fn redo(&self) {}
fn get_description(&self) -> String {
String::from("A simple command that clears the terminal")
}
fn get_name(&self) -> String {
String::from("clear")
}
fn get_help(&self) -> String {
String::from("Clears the terminal")
}
fn get_params(&self) -> String {
String::from("None")
}
2024-12-01 16:02:06 -05:00
}
#[derive(Default)]
pub struct ExitCommand;
impl Command for ExitCommand {
fn execute(&self, args: Option<Vec<String>>) -> Result<(), ZenyxError> {
match args {
Some(args) => {
let exit_code = args[0].parse().map_err(|e| {
ZenyxError::builder(ZenyxErrorKind::CommandParsing)
.with_message("Failed to parse exit code")
.with_source(e)
.build()
})?;
std::process::exit(exit_code);
}
None => {
std::process::exit(0);
}
}
}
fn undo(&self) {
todo!()
}
fn redo(&self) {
todo!()
}
fn get_description(&self) -> String {
String::from("Gracefully exists the program")
}
fn get_name(&self) -> String {
String::from("exit")
}
fn get_help(&self) -> String {
String::from("Exits, probably")
}
fn get_params(&self) -> String {
String::from("None")
}
2024-12-01 16:02:06 -05:00
}
#[derive(Default)]
pub struct ExecFile;
impl Command for ExecFile {
fn execute(&self, args: Option<Vec<String>>) -> Result<(), ZenyxError> {
match args {
Some(args) => {
let file_path = PathBuf::from_str(&args[0]).map_err(|e| {
ZenyxError::builder(ZenyxErrorKind::CommandParsing)
.with_message("Invalid file path")
.with_source(e)
.build()
})?;
if file_path.extension().is_some() && file_path.extension().unwrap() != "zensh" {
return Err(ZenyxError::builder(ZenyxErrorKind::CommandParsing)
.with_message("Selected file was not a zensh file")
.build());
} else {
let zscript = fs::read_to_string(file_path).map_err(|e| {
ZenyxError::builder(ZenyxErrorKind::Io)
.with_message("Failed to read file")
.with_source(e)
.build()
})?;
if let Ok(command) = eval(zscript) {
println!("{:#?}", command);
for (cmd_name, cmd_args) in command {
match COMMAND_MANAGER.read().execute(&cmd_name, cmd_args) {
Ok(_) => (),
Err(e) => {
println!(
"Error executing command returned an error: {}. Aborting script",
e
);
break;
}
}
}
}
}
Ok(())
}
None => Err(ZenyxError::builder(ZenyxErrorKind::CommandParsing)
.with_message("Not enough arguments")
.build()),
}
}
fn undo(&self) {}
fn redo(&self) {}
fn get_description(&self) -> String {
String::from("Executes a file path")
}
fn get_name(&self) -> String {
String::from("exec")
}
fn get_help(&self) -> String {
String::from("this will read the contents of a .zensh file, evaluate it, and run its input")
}
fn get_params(&self) -> String {
String::from("1: File path")
}
2024-12-01 16:02:06 -05:00
}
#[derive(Default)]
pub struct CounterCommand {
counter: RwLock<u32>,
2024-12-01 16:02:06 -05:00
}
impl Command for CounterCommand {
fn execute(&self, _args: Option<Vec<String>>) -> Result<(), ZenyxError> {
// Increment the counter
let mut count = self.counter.write();
*count += 1;
println!("CounterCommand executed. Current count: {}", *count);
Ok(())
}
fn undo(&self) {
println!("Undo CounterCommand.");
}
fn redo(&self) {
println!("Redo CounterCommand.");
}
fn get_description(&self) -> String {
String::from("counter")
}
fn get_help(&self) -> String {
String::from("Increments a counter every time it's executed.")
}
fn get_params(&self) -> String {
String::from("No parameters for CounterCommand.")
}
fn get_name(&self) -> String {
String::from("count")
}
}
#[derive(Default)]
pub struct PanicCommmand;
impl Command for PanicCommmand {
fn execute(&self, args: Option<Vec<String>>) -> Result<(), ZenyxError> {
if args.is_some() {
let panic_msg = &args.unwrap()[0];
panic!("{}", panic_msg)
}
let option: Option<i32> = None;
println!("Unwrapping None: {}", option.unwrap());
panic!("Panic command was called")
}
fn undo(&self) {}
fn redo(&self) {}
fn get_description(&self) -> String {
String::from("causes a panic with your provided message")
}
fn get_name(&self) -> String {
String::from("panic")
}
fn get_help(&self) -> String {
String::from("")
}
fn get_params(&self) -> String {
String::from("optional: panic msg")
}
}
fn eval(input: String) -> Result<Vec<(String, Option<Vec<String>>)>, ZenyxError> {
if input.trim().is_empty() {
return Err(ZenyxError::builder(ZenyxErrorKind::CommandParsing)
.with_message("Input was empty")
.build());
}
let pattern = Regex::new(r"[;|\n]").map_err(|e| {
ZenyxError::builder(ZenyxErrorKind::CommandParsing)
.with_message("Failed to compile regex")
.with_source(e)
.build()
})?;
let commands: Vec<&str> = pattern.split(&input).collect();
let mut evaluted = vec![];
for command in commands {
let command = command.trim();
if command.is_empty() {
println!("Empty command, skipping.");
continue;
}
let tokens = tokenize(command);
if tokens.is_empty() {
println!("Empty command, skipping.");
continue;
}
let cmd_name = &tokens[0];
let args: Option<Vec<String>> = if tokens.len() > 1 {
Some(tokens[1..].iter().map(|s| s.to_string()).collect())
} else {
None
};
2024-12-21 16:28:32 -05:00
evaluted.push((cmd_name.to_owned(), args));
}
Ok(evaluted)
}