feat: basic GUI terminal when pressing F12
This commit is contained in:
parent
bb9bca8ca5
commit
0acbbcf9f6
15 changed files with 808 additions and 826 deletions
|
@ -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) {}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue