forked from nonsensical-dev/zenyx-engine
Merge pull request from eatmynerds/repl
Add descriptions to commands and improve REPL display formatting
This commit is contained in:
commit
d449c61643
7 changed files with 323 additions and 292 deletions
|
@ -1,16 +1,14 @@
|
||||||
pub mod commands;
|
|
||||||
pub mod repl;
|
|
||||||
pub mod splash;
|
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
|
pub mod repl;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use renderer::App;
|
use renderer::App;
|
||||||
use winit::event_loop::{ControlFlow, EventLoop};
|
use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn init_renderer() -> Result<()> {
|
pub fn init_renderer() -> Result<()> {
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
event_loop.set_control_flow(ControlFlow::Poll);
|
event_loop.set_control_flow(ControlFlow::Poll);
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
Ok(event_loop.run_app(&mut app)?)
|
Ok(event_loop.run_app(&mut app)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,248 +0,0 @@
|
||||||
use super::commands;
|
|
||||||
use chrono::Local;
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use log2::{debug, error, info};
|
|
||||||
use parking_lot::RwLock;
|
|
||||||
use reedline::{Prompt, Reedline, Signal};
|
|
||||||
use regex::Regex;
|
|
||||||
use std::{borrow::Borrow, collections::HashMap, sync::Arc};
|
|
||||||
|
|
||||||
struct ZPrompt {
|
|
||||||
left_text: String,
|
|
||||||
right_text: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum Callable {
|
|
||||||
Simple(fn()),
|
|
||||||
WithArgs(fn(Vec<String>)),
|
|
||||||
}
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Command {
|
|
||||||
pub name: &'static str,
|
|
||||||
pub description: Option<&'static str>,
|
|
||||||
function: Callable,
|
|
||||||
pub arg_count: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command {
|
|
||||||
pub fn execute(&self, args: Option<Vec<String>>) {
|
|
||||||
//debug!("Executing command: {}", self.name);
|
|
||||||
match &self.function {
|
|
||||||
Callable::Simple(f) => {
|
|
||||||
if let Some(args) = args {
|
|
||||||
error!(
|
|
||||||
"Command expected 0 arguments but {} args were given. Ignoring..",
|
|
||||||
args.len()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
Callable::WithArgs(f) => match args {
|
|
||||||
Some(args) => f(args),
|
|
||||||
None => error!("Command expected arguments but received 0"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Command {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Name: {}\n\t{}",
|
|
||||||
self.name,
|
|
||||||
self.description.unwrap_or("No description")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref COMMAND_LIST: Arc<CommandList> = Arc::new(CommandList::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CommandList {
|
|
||||||
pub commands: RwLock<Vec<Command>>,
|
|
||||||
pub aliases: RwLock<HashMap<String, String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandList {
|
|
||||||
fn new() -> Self {
|
|
||||||
CommandList {
|
|
||||||
commands: RwLock::new(Vec::new()),
|
|
||||||
aliases: RwLock::new(HashMap::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_command(
|
|
||||||
&self,
|
|
||||||
name: &'static str,
|
|
||||||
description: Option<&'static str>,
|
|
||||||
func: Callable,
|
|
||||||
arg_count: Option<u8>,
|
|
||||||
) {
|
|
||||||
debug!("Adding command: {}", name);
|
|
||||||
let mut commands = self.commands.write();
|
|
||||||
|
|
||||||
commands.push(Command {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
function: func,
|
|
||||||
arg_count: arg_count.unwrap_or(0),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
fn add_alias(&self, name: String, alias: String) {
|
|
||||||
//println!("Input alias: {}", alias);
|
|
||||||
if self.aliases.read().contains_key(&alias) {
|
|
||||||
error!("Alias: '{}' already exists", alias);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut commands = self.commands.write();
|
|
||||||
if let Some(command) = commands.iter_mut().find(|cmd| cmd.name == name) {
|
|
||||||
info!("Adding alias: {} for cmd: {}", alias, command.name);
|
|
||||||
self.aliases
|
|
||||||
.write()
|
|
||||||
.insert(alias.to_string(), name.to_string());
|
|
||||||
} else {
|
|
||||||
error!("Command: '{}' was not found", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_command(&self, mut name: String, args: Option<Vec<String>>) {
|
|
||||||
//info!("received input command: {}", name);
|
|
||||||
let commands = self.commands.borrow();
|
|
||||||
if self.aliases.read().contains_key(&name) {
|
|
||||||
name = self
|
|
||||||
.aliases
|
|
||||||
.read()
|
|
||||||
.get_key_value(&name)
|
|
||||||
.unwrap()
|
|
||||||
.1
|
|
||||||
.to_string();
|
|
||||||
debug!("changed to {}", name);
|
|
||||||
}
|
|
||||||
if let Some(command) = commands.read().iter().find(|cmd| cmd.name == name) { match (command.arg_count, args.as_ref()) {
|
|
||||||
(expected, Some(args_vec)) if args_vec.len() != expected as usize => {
|
|
||||||
eprintln!(
|
|
||||||
"Command: '{}' expected {} arguments but received {}",
|
|
||||||
name,
|
|
||||||
expected,
|
|
||||||
args_vec.len()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(_, _) => command.execute(args),
|
|
||||||
} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Prompt for ZPrompt {
|
|
||||||
fn render_prompt_left(&self) -> std::borrow::Cow<str> {
|
|
||||||
std::borrow::Cow::Borrowed(&self.left_text)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_prompt_right(&self) -> std::borrow::Cow<str> {
|
|
||||||
std::borrow::Cow::Borrowed(&self.right_text)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_prompt_history_search_indicator(
|
|
||||||
&self,
|
|
||||||
_history_search: reedline::PromptHistorySearch,
|
|
||||||
) -> std::borrow::Cow<str> {
|
|
||||||
std::borrow::Cow::Borrowed("")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_prompt_indicator(
|
|
||||||
&self,
|
|
||||||
prompt_mode: reedline::PromptEditMode,
|
|
||||||
) -> std::borrow::Cow<str> {
|
|
||||||
match prompt_mode {
|
|
||||||
reedline::PromptEditMode::Default => std::borrow::Cow::Borrowed(">>"),
|
|
||||||
reedline::PromptEditMode::Emacs => {
|
|
||||||
let timestamp = Local::now().format("[%H:%M:%S.%3f/SHELL] >>\t").to_string();
|
|
||||||
std::borrow::Cow::Owned(timestamp)
|
|
||||||
}
|
|
||||||
reedline::PromptEditMode::Vi(_) => std::borrow::Cow::Borrowed("vi>>"),
|
|
||||||
reedline::PromptEditMode::Custom(_) => std::borrow::Cow::Borrowed("custom>>"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_prompt_multiline_indicator(&self) -> std::borrow::Cow<str> {
|
|
||||||
std::borrow::Cow::Borrowed("><")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup() {
|
|
||||||
COMMAND_LIST.add_command(
|
|
||||||
"hello",
|
|
||||||
Some("test"),
|
|
||||||
Callable::Simple(commands::say_hello),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
COMMAND_LIST.add_command("exit", None, Callable::Simple(commands::exit), None);
|
|
||||||
COMMAND_LIST.add_command("clear", None, Callable::Simple(commands::clear), None);
|
|
||||||
COMMAND_LIST.add_command("echo", None, Callable::WithArgs(commands::echo), Some(1));
|
|
||||||
COMMAND_LIST.add_command("cmds", None, Callable::Simple(commands::cmds), None);
|
|
||||||
COMMAND_LIST.add_alias("cmds".to_string(), "help".to_string());
|
|
||||||
COMMAND_LIST.add_alias("cmds".to_string(), "cmd_list".to_string());
|
|
||||||
COMMAND_LIST.add_alias("hello".to_string(), "exit".to_string());
|
|
||||||
COMMAND_LIST.add_alias("clear".to_string(), "exit".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_repl() {
|
|
||||||
let mut line_editor = Reedline::create();
|
|
||||||
setup();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let sig = line_editor.read_line(&ZPrompt {
|
|
||||||
left_text: String::new(),
|
|
||||||
right_text: "<<".to_string(),
|
|
||||||
});
|
|
||||||
|
|
||||||
match sig {
|
|
||||||
Ok(Signal::Success(buffer)) => {
|
|
||||||
if buffer == "exit" {
|
|
||||||
std::process::exit(0);
|
|
||||||
} else {
|
|
||||||
evaluate_command(&buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Signal::CtrlC) => {
|
|
||||||
println!("\nCONTROL+C RECEIVED, TERMINATING");
|
|
||||||
std::process::exit(0);
|
|
||||||
}
|
|
||||||
err => {
|
|
||||||
eprintln!("Error: {:?}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn evaluate_command(input: &str) {
|
|
||||||
if input.trim().is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pattern = Regex::new(r"[;|\n]").unwrap();
|
|
||||||
let commands: Vec<&str> = pattern.split(input).collect();
|
|
||||||
|
|
||||||
for command in commands {
|
|
||||||
let command = command.trim();
|
|
||||||
if command.is_empty() {
|
|
||||||
println!("Empty command, skipping.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let tokens: Vec<&str> = command.split_whitespace().collect();
|
|
||||||
if tokens.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd_name = tokens[0];
|
|
||||||
let args: Vec<String> = tokens[1..].iter().map(|&s| s.to_string()).collect();
|
|
||||||
|
|
||||||
COMMAND_LIST.execute_command(
|
|
||||||
cmd_name.to_string(),
|
|
||||||
if args.is_empty() { None } else { Some(args) },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +1,34 @@
|
||||||
|
use super::COMMAND_LIST;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use log2::{debug, info};
|
use log2::{debug, info};
|
||||||
|
|
||||||
use crate::core::repl::COMMAND_LIST;
|
pub(crate) fn say_hello() {
|
||||||
|
println!("Hello, World!");
|
||||||
pub fn say_hello() {
|
|
||||||
println!("Hello from your new command!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn echo(args: Vec<String>) {
|
pub(crate) fn echo(args: Vec<String>) {
|
||||||
debug!("{}", args.join(" "));
|
debug!("{}", args.join(" "));
|
||||||
println!("{}", args.join(" "))
|
println!("{}", args.join(" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit() {
|
pub(crate) fn exit() {
|
||||||
debug!("Exiting...");
|
debug!("Exiting...");
|
||||||
std::process::exit(0)
|
std::process::exit(0)
|
||||||
}
|
}
|
||||||
pub fn clear() {
|
|
||||||
|
pub(crate) fn clear() {
|
||||||
info!("Clearing screen..., running command");
|
info!("Clearing screen..., running command");
|
||||||
let _result = if cfg!(target_os = "windows") {
|
let _result = if cfg!(target_os = "windows") {
|
||||||
debug!("target_os is windows");
|
debug!("target_os is windows");
|
||||||
Command::new("cmd").args(["/c", "cls"]).spawn()
|
Command::new("cmd").args(["/c", "cls"]).spawn()
|
||||||
} else {
|
} else {
|
||||||
debug!("target_os was unix");
|
debug!("target_os is unix");
|
||||||
// "clear" or "tput reset"
|
// "clear" or "tput reset"
|
||||||
Command::new("tput").arg("reset").spawn()
|
Command::new("tput").arg("reset").spawn()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn cmds() {
|
|
||||||
|
pub(crate) fn help() {
|
||||||
println!("Commands:");
|
println!("Commands:");
|
||||||
for cmd in COMMAND_LIST.commands.read().iter() {
|
for cmd in COMMAND_LIST.commands.read().iter() {
|
||||||
println!("{:#}", cmd);
|
println!("{:#}", cmd);
|
135
engine/src/core/repl/mod.rs
Normal file
135
engine/src/core/repl/mod.rs
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
pub mod commands;
|
||||||
|
pub mod repl;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use log2::{debug, error, info};
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use std::{borrow::Borrow, collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref COMMAND_LIST: Arc<CommandList> = Arc::new(CommandList::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum Callable {
|
||||||
|
Simple(fn()),
|
||||||
|
WithArgs(fn(Vec<String>)),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Command {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub description: Option<&'static str>,
|
||||||
|
function: Callable,
|
||||||
|
pub arg_count: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
pub fn execute(&self, args: Option<Vec<String>>) {
|
||||||
|
//debug!("Executing command: {}", self.name);
|
||||||
|
match &self.function {
|
||||||
|
Callable::Simple(f) => {
|
||||||
|
if let Some(args) = args {
|
||||||
|
error!(
|
||||||
|
"Command expected 0 arguments but {} args were given. Ignoring..",
|
||||||
|
args.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
Callable::WithArgs(f) => match args {
|
||||||
|
Some(args) => f(args),
|
||||||
|
None => error!("Command expected arguments but received 0"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Command {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
" {:<10} {}",
|
||||||
|
self.name,
|
||||||
|
self.description.unwrap_or("No description available")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CommandList {
|
||||||
|
pub commands: RwLock<Vec<Command>>,
|
||||||
|
pub aliases: RwLock<HashMap<String, String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandList {
|
||||||
|
fn new() -> Self {
|
||||||
|
CommandList {
|
||||||
|
commands: RwLock::new(Vec::new()),
|
||||||
|
aliases: RwLock::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_command(
|
||||||
|
&self,
|
||||||
|
name: &'static str,
|
||||||
|
description: Option<&'static str>,
|
||||||
|
func: Callable,
|
||||||
|
arg_count: Option<u8>,
|
||||||
|
) {
|
||||||
|
debug!("Adding command: {}", name);
|
||||||
|
let mut commands = self.commands.write();
|
||||||
|
|
||||||
|
commands.push(Command {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
function: func,
|
||||||
|
arg_count: arg_count.unwrap_or(0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_alias(&self, name: String, alias: String) {
|
||||||
|
//println!("Input alias: {}", alias);
|
||||||
|
if self.aliases.read().contains_key(&alias) {
|
||||||
|
error!("Alias: '{}' already exists", alias);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut commands = self.commands.write();
|
||||||
|
if let Some(command) = commands.iter_mut().find(|cmd| cmd.name == name) {
|
||||||
|
info!("Adding alias: {} for cmd: {}", alias, command.name);
|
||||||
|
self.aliases
|
||||||
|
.write()
|
||||||
|
.insert(alias.to_string(), name.to_string());
|
||||||
|
} else {
|
||||||
|
error!("Command: '{}' was not found", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_command(&self, mut name: String, args: Option<Vec<String>>) {
|
||||||
|
//info!("received input command: {}", name);
|
||||||
|
let commands = self.commands.borrow();
|
||||||
|
if self.aliases.read().contains_key(&name) {
|
||||||
|
name = self
|
||||||
|
.aliases
|
||||||
|
.read()
|
||||||
|
.get_key_value(&name)
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
debug!("changed to {}", name);
|
||||||
|
}
|
||||||
|
if let Some(command) = commands.read().iter().find(|cmd| cmd.name == name) {
|
||||||
|
match (command.arg_count, args.as_ref()) {
|
||||||
|
(expected, Some(args_vec)) if args_vec.len() != expected as usize => {
|
||||||
|
eprintln!(
|
||||||
|
"Command: '{}' expected {} arguments but received {}",
|
||||||
|
name,
|
||||||
|
expected,
|
||||||
|
args_vec.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(_, _) => command.execute(args),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
146
engine/src/core/repl/repl.rs
Normal file
146
engine/src/core/repl/repl.rs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
use super::{commands, Callable, COMMAND_LIST};
|
||||||
|
use chrono::Local;
|
||||||
|
use reedline::{Prompt, Reedline, Signal};
|
||||||
|
use regex::Regex;
|
||||||
|
use std::{borrow::Borrow, collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
|
fn register_commands() {
|
||||||
|
COMMAND_LIST.add_command(
|
||||||
|
"hello",
|
||||||
|
Some("Displays \"Hello World\"!"),
|
||||||
|
Callable::Simple(commands::say_hello),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMAND_LIST.add_command(
|
||||||
|
"exit",
|
||||||
|
Some("Exits the application gracefully."),
|
||||||
|
Callable::Simple(commands::exit),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMAND_LIST.add_command(
|
||||||
|
"clear",
|
||||||
|
Some("Clears the terminal screen."),
|
||||||
|
Callable::Simple(commands::clear),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMAND_LIST.add_command(
|
||||||
|
"echo",
|
||||||
|
Some("Prints the provided arguments back to the terminal."),
|
||||||
|
Callable::WithArgs(commands::echo),
|
||||||
|
Some(1), // Requires at least one argument
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMAND_LIST.add_command(
|
||||||
|
"help",
|
||||||
|
Some("Displays a list of all available commands."),
|
||||||
|
Callable::Simple(commands::help),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
// EXAMPLE
|
||||||
|
// Adding aliases for commands
|
||||||
|
COMMAND_LIST.add_alias("cls".to_string(), "clear".to_string()); // Likely unintended; consider removing or renaming.
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ZPrompt {
|
||||||
|
left_text: String,
|
||||||
|
right_text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Prompt for ZPrompt {
|
||||||
|
fn render_prompt_left(&self) -> std::borrow::Cow<str> {
|
||||||
|
std::borrow::Cow::Borrowed(&self.left_text)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_prompt_right(&self) -> std::borrow::Cow<str> {
|
||||||
|
std::borrow::Cow::Borrowed(&self.right_text)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_prompt_history_search_indicator(
|
||||||
|
&self,
|
||||||
|
_history_search: reedline::PromptHistorySearch,
|
||||||
|
) -> std::borrow::Cow<str> {
|
||||||
|
std::borrow::Cow::Borrowed("")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_prompt_indicator(
|
||||||
|
&self,
|
||||||
|
prompt_mode: reedline::PromptEditMode,
|
||||||
|
) -> std::borrow::Cow<str> {
|
||||||
|
match prompt_mode {
|
||||||
|
reedline::PromptEditMode::Default => std::borrow::Cow::Borrowed(">>"),
|
||||||
|
reedline::PromptEditMode::Emacs => {
|
||||||
|
let timestamp = Local::now().format("[%H:%M:%S.%3f/SHELL] >>\t").to_string();
|
||||||
|
std::borrow::Cow::Owned(timestamp)
|
||||||
|
}
|
||||||
|
reedline::PromptEditMode::Vi(_) => std::borrow::Cow::Borrowed("vi>>"),
|
||||||
|
reedline::PromptEditMode::Custom(_) => std::borrow::Cow::Borrowed("custom>>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_prompt_multiline_indicator(&self) -> std::borrow::Cow<str> {
|
||||||
|
std::borrow::Cow::Borrowed("><")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evaluate_command(input: &str) {
|
||||||
|
if input.trim().is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pattern = Regex::new(r"[;|\n]").unwrap();
|
||||||
|
let commands: Vec<&str> = pattern.split(input).collect();
|
||||||
|
|
||||||
|
for command in commands {
|
||||||
|
let command = command.trim();
|
||||||
|
if command.is_empty() {
|
||||||
|
println!("Empty command, skipping.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tokens: Vec<&str> = command.split_whitespace().collect();
|
||||||
|
if tokens.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmd_name = tokens[0];
|
||||||
|
let args: Vec<String> = tokens[1..].iter().map(|&s| s.to_string()).collect();
|
||||||
|
|
||||||
|
COMMAND_LIST.execute_command(
|
||||||
|
cmd_name.to_string(),
|
||||||
|
if args.is_empty() { None } else { Some(args) },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_repl() {
|
||||||
|
let mut line_editor = Reedline::create();
|
||||||
|
register_commands();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let sig = line_editor.read_line(&ZPrompt {
|
||||||
|
left_text: String::new(),
|
||||||
|
right_text: "<<".to_string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
match sig {
|
||||||
|
Ok(Signal::Success(buffer)) => {
|
||||||
|
if buffer == "exit" {
|
||||||
|
std::process::exit(0);
|
||||||
|
} else {
|
||||||
|
evaluate_command(&buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Signal::CtrlC) => {
|
||||||
|
println!("\nCONTROL+C RECEIVED, TERMINATING");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
err => {
|
||||||
|
eprintln!("Error: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
use colored::Colorize;
|
|
||||||
|
|
||||||
pub fn print_splash() {
|
|
||||||
println!(
|
|
||||||
r#"
|
|
||||||
&&&&&&&&&&&
|
|
||||||
&&&&&&&&&&&&&&&&&
|
|
||||||
&&&&&&&&&&&&&&&&&&&&&
|
|
||||||
&& &&&&&&&&&
|
|
||||||
&& &&&&&&&&&
|
|
||||||
&&&&&&&&&&&& &&&&&&&&&&&
|
|
||||||
&&&&&&&&&&&&& &&&&&&&&&&&&
|
|
||||||
&&&&&&&&&&&&& &&&&&&&&&&&&&
|
|
||||||
&&&&&&&&&&&& &&&&&&&&&&&&&
|
|
||||||
&&&&&&&&&&& &&&&&&&&&&&&
|
|
||||||
&&&&&&&&& &&
|
|
||||||
&&&&&&&&& &&
|
|
||||||
&&&&&&&&&&&&&&&&&&&&&
|
|
||||||
&&&&&&&&&&&&&&&&&
|
|
||||||
&&&&&&&&&&&
|
|
||||||
|
|
||||||
Version: {}
|
|
||||||
"#,
|
|
||||||
env!("CARGO_PKG_VERSION").yellow().italic().underline()
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,18 +1,44 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use colored::Colorize;
|
||||||
use log2::info;
|
use log2::info;
|
||||||
|
|
||||||
pub mod core;
|
pub mod core;
|
||||||
|
|
||||||
|
pub fn print_splash() {
|
||||||
|
println!(
|
||||||
|
r#"
|
||||||
|
&&&&&&&&&&&
|
||||||
|
&&&&&&&&&&&&&&&&&
|
||||||
|
&&&&&&&&&&&&&&&&&&&&&
|
||||||
|
&& &&&&&&&&&
|
||||||
|
&& &&&&&&&&&
|
||||||
|
&&&&&&&&&&&& &&&&&&&&&&&
|
||||||
|
&&&&&&&&&&&&& &&&&&&&&&&&&
|
||||||
|
&&&&&&&&&&&&& &&&&&&&&&&&&&
|
||||||
|
&&&&&&&&&&&& &&&&&&&&&&&&&
|
||||||
|
&&&&&&&&&&& &&&&&&&&&&&&
|
||||||
|
&&&&&&&&& &&
|
||||||
|
&&&&&&&&& &&
|
||||||
|
&&&&&&&&&&&&&&&&&&&&&
|
||||||
|
&&&&&&&&&&&&&&&&&
|
||||||
|
&&&&&&&&&&&
|
||||||
|
|
||||||
|
Version: {}
|
||||||
|
"#,
|
||||||
|
env!("CARGO_PKG_VERSION").yellow().italic().underline()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let _log2 = log2::open("z.log").tee(true).level("debug").start();
|
let _log2 = log2::open("z.log").tee(true).level("debug").start();
|
||||||
info!("Initalizing Engine");
|
info!("Initalizing Engine");
|
||||||
let shell_thread = tokio::task::spawn(async {
|
let shell_thread = tokio::task::spawn(async {
|
||||||
info!("Shell thread started");
|
info!("Shell thread started");
|
||||||
core::repl::handle_repl().await;
|
core::repl::repl::handle_repl().await;
|
||||||
});
|
});
|
||||||
|
|
||||||
core::splash::print_splash();
|
print_splash();
|
||||||
info!("Engine Initalized");
|
info!("Engine Initalized");
|
||||||
core::init_renderer()?;
|
core::init_renderer()?;
|
||||||
shell_thread.await?;
|
shell_thread.await?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue