feat: basic GUI terminal when pressing F12

This commit is contained in:
Chance 2025-04-10 14:26:52 -04:00
parent bb9bca8ca5
commit 0acbbcf9f6
Signed by: caznix
GPG key ID: 489D213143D753FD
15 changed files with 808 additions and 826 deletions

View file

@ -10,27 +10,28 @@ use crate::error::{ZenyxError, ZenyxErrorKind};
pub struct HelpCommand;
impl Command for HelpCommand {
fn execute(&self, _args: Option<Vec<String>>) -> Result<(), ZenyxError> {
fn execute(&self, _args: Option<Vec<String>>) -> Result<String, ZenyxError> {
let manager = COMMAND_MANAGER.read();
println!("Available commands:\n");
let mut output = String::new();
output.push_str("Available commands:\n\n");
for (_, command) in manager.get_commands() {
println!(
"Command: {}\n\tDescription: {}\n\tParameters: {}\n\tHelp: {}\n",
output.push_str(&format!(
"Command: {}\n\tDescription: {}\n\tParameters: {}\n\tHelp: {}\n\n",
command.get_name().to_lowercase(),
command.get_description(),
command.get_params(),
command.get_help()
);
));
}
if !manager.aliases.is_empty() {
println!("Aliases:");
output.push_str("Aliases:\n");
for (alias, command) in &manager.aliases {
println!("\t{} -> {}", alias, command);
output.push_str(&format!("\t{} -> {}\n", alias, command));
}
}
Ok(())
Ok(output)
}
fn undo(&self) {}
@ -58,8 +59,7 @@ impl Command for HelpCommand {
pub struct ClearCommand;
impl Command for ClearCommand {
fn execute(&self, _args: Option<Vec<String>>) -> Result<(), ZenyxError> {
println!("Clearing screen..., running command");
fn execute(&self, _args: Option<Vec<String>>) -> Result<String, ZenyxError> {
let _result = if cfg!(target_os = "windows") {
std::process::Command::new("cmd")
.args(["/c", "cls"])
@ -67,7 +67,7 @@ impl Command for ClearCommand {
} else {
std::process::Command::new("clear").spawn()
};
Ok(())
Ok(String::from("Screen cleared."))
}
fn undo(&self) {}
@ -95,7 +95,7 @@ impl Command for ClearCommand {
pub struct ExitCommand;
impl Command for ExitCommand {
fn execute(&self, args: Option<Vec<String>>) -> Result<(), ZenyxError> {
fn execute(&self, args: Option<Vec<String>>) -> Result<String, ZenyxError> {
match args {
Some(args) => {
let exit_code = args[0].parse().map_err(|e| {
@ -141,7 +141,7 @@ impl Command for ExitCommand {
pub struct ExecFile;
impl Command for ExecFile {
fn execute(&self, args: Option<Vec<String>>) -> Result<(), ZenyxError> {
fn execute(&self, args: Option<Vec<String>>) -> Result<String, ZenyxError> {
match args {
Some(args) => {
let file_path = PathBuf::from_str(&args[0]).map_err(|e| {
@ -161,23 +161,30 @@ impl Command for ExecFile {
.with_source(e)
.build()
})?;
if let Ok(command) = eval(zscript) {
println!("{:#?}", command);
for (cmd_name, cmd_args) in command {
let mut script_output = String::new();
if let Ok(commands_to_execute) = eval(zscript) {
for (cmd_name, cmd_args) in commands_to_execute {
match COMMAND_MANAGER.read().execute(&cmd_name, cmd_args) {
Ok(_) => (),
Ok(output) => script_output.push_str(&output),
Err(e) => {
println!(
"Error executing command returned an error: {}. Aborting script",
e
);
break;
return Err(ZenyxError::builder(
ZenyxErrorKind::CommandExecution,
)
.with_message(format!(
"Error executing command '{}' in script: {}",
cmd_name, e
))
.build());
}
}
}
return Ok(script_output);
} else {
return Err(ZenyxError::builder(ZenyxErrorKind::CommandExecution)
.with_message("Failed to evaluate script")
.build());
}
}
Ok(())
}
None => Err(ZenyxError::builder(ZenyxErrorKind::CommandParsing)
.with_message("Not enough arguments")
@ -212,12 +219,13 @@ pub struct CounterCommand {
}
impl Command for CounterCommand {
fn execute(&self, _args: Option<Vec<String>>) -> Result<(), ZenyxError> {
// Increment the counter
fn execute(&self, _args: Option<Vec<String>>) -> Result<String, ZenyxError> {
let mut count = self.counter.write();
*count += 1;
println!("CounterCommand executed. Current count: {}", *count);
Ok(())
Ok(format!(
"CounterCommand executed. Current count: {}",
*count
))
}
fn undo(&self) {
@ -248,14 +256,15 @@ impl Command for CounterCommand {
#[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)
fn execute(&self, args: Option<Vec<String>>) -> Result<String, ZenyxError> {
if let Some(args) = args {
let panic_msg = &args[0];
panic!("{}", panic_msg);
} else {
let option: Option<i32> = None;
println!("Unwrapping None: {}", option.unwrap());
panic!("Panic command was called");
}
let option: Option<i32> = None;
println!("Unwrapping None: {}", option.unwrap());
panic!("Panic command was called")
}
fn undo(&self) {}

View file

@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::sync::LazyLock;
use ahash::AHashMap;
use colored::Colorize;
use parking_lot::RwLock;
@ -93,15 +93,15 @@ fn check_similarity(target: &str) -> Option<String> {
}
pub struct CommandManager {
pub commands: HashMap<String, Box<dyn Command>>,
pub aliases: HashMap<String, String>,
pub commands: AHashMap<String, Box<dyn Command>>,
pub aliases: AHashMap<String, String>,
}
impl CommandManager {
pub fn init() -> CommandManager {
CommandManager {
commands: HashMap::new(),
aliases: HashMap::new(),
commands: AHashMap::new(),
aliases: AHashMap::new(),
}
}
@ -113,10 +113,10 @@ impl CommandManager {
&self,
command: &str,
args: Option<Vec<String>>,
) -> Result<(), ZenyxError> {
) -> Result<String, ZenyxError> {
if let Some(command) = self.commands.get(command) {
command.execute(args)?;
Ok(())
let output = command.execute(args)?;
Ok(output)
} else {
let corrected_cmd = check_similarity(command);
if let Some(corrected_cmd) = corrected_cmd {
@ -132,12 +132,12 @@ impl CommandManager {
}
}
pub fn execute(&self, command: &str, args: Option<Vec<String>>) -> Result<(), ZenyxError> {
pub fn execute(&self, command: &str, args: Option<Vec<String>>) -> Result<String, ZenyxError> {
match self.aliases.get(command) {
Some(command) => self.execute(command, args),
None => {
self.execute_command(command, args)?;
Ok(())
let output = self.execute_command(command, args)?;
Ok(output)
}
}
}
@ -156,7 +156,7 @@ impl CommandManager {
}
pub trait Command: Send + Sync {
fn execute(&self, args: Option<Vec<String>>) -> Result<(), ZenyxError>;
fn execute(&self, args: Option<Vec<String>>) -> Result<String, ZenyxError>;
fn undo(&self);
fn redo(&self);
fn get_description(&self) -> String;

View file

@ -16,13 +16,8 @@ use tracing::{debug, error, info, warn};
use super::handler::COMMAND_MANAGER;
use crate::error::{Result, ZenyxError, ZenyxErrorKind};
#[derive(Default)]
struct CommandCompleter;
impl CommandCompleter {
fn new() -> Self {
CommandCompleter {}
}
}
impl Completer for CommandCompleter {
type Candidate = String;
@ -138,15 +133,19 @@ pub fn parse_command(input: &str) -> Result<Vec<String>> {
Ok(commands)
}
pub fn evaluate_command(input: &str) -> Result<()> {
pub fn evaluate_command(input: &str) -> std::result::Result<String, ZenyxError> {
if input.trim().is_empty() {
return Ok(());
let err = ZenyxError::builder(ZenyxErrorKind::CommandParsing)
.with_message("Input was empty")
.build();
return Err(err);
}
let commands = input
.split(|c| c == ';' || c == '\n')
.map(|slice| slice.to_string())
.collect::<Vec<String>>();
let mut output = String::new();
for command in commands {
let command = command.trim();
@ -166,20 +165,16 @@ pub fn evaluate_command(input: &str) -> Result<()> {
} else {
None
};
COMMAND_MANAGER
.read()
.execute(cmd_name, args)
.map_err(|e| {
ZenyxError::builder(ZenyxErrorKind::CommandExecution)
.with_message(format!("Failed to execute command: {cmd_name}"))
.with_context(format!("{e}"))
.build()
})?;
match COMMAND_MANAGER.read().execute(cmd_name, args) {
Ok(command_output) => output.push_str(&command_output),
Err(e) => {
return Err(e);
}
}
}
Ok(())
Ok(output)
}
fn format_time() -> String {
pub fn format_time() -> String {
let now = SystemTime::now();
let duration = now.duration_since(UNIX_EPOCH).unwrap();
let total_seconds = duration.as_secs();
@ -201,7 +196,7 @@ pub async fn handle_repl() -> Result<()> {
let mut rl = Editor::<MyHelper, DefaultHistory>::new()?;
rl.set_helper(Some(MyHelper {
hinter: HistoryHinter::new(),
completer: CommandCompleter::new(),
completer: CommandCompleter::default(),
}));
rl.bind_sequence(
@ -218,6 +213,7 @@ pub async fn handle_repl() -> Result<()> {
loop {
let time = format_time();
let prompt = format!("[{}/{}] {}", time, "SHELL", ">>\t");
let sig = rl.readline(&prompt.bright_white());
match sig {