Merge pull request from eatmynerds/repl
Add descriptions to commands and improve REPL display formatting
This commit is contained in:
commit
3ad52908e6
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 repl;
|
||||
|
||||
use anyhow::Result;
|
||||
use renderer::App;
|
||||
use winit::event_loop::{ControlFlow, EventLoop};
|
||||
|
||||
|
||||
|
||||
pub fn init_renderer() -> Result<()> {
|
||||
let event_loop = EventLoop::new().unwrap();
|
||||
event_loop.set_control_flow(ControlFlow::Poll);
|
||||
let mut app = App::default();
|
||||
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 log2::{debug, info};
|
||||
|
||||
use crate::core::repl::COMMAND_LIST;
|
||||
|
||||
pub fn say_hello() {
|
||||
println!("Hello from your new command!");
|
||||
pub(crate) fn say_hello() {
|
||||
println!("Hello, World!");
|
||||
}
|
||||
|
||||
pub fn echo(args: Vec<String>) {
|
||||
pub(crate) fn echo(args: Vec<String>) {
|
||||
debug!("{}", args.join(" "));
|
||||
println!("{}", args.join(" "))
|
||||
}
|
||||
|
||||
pub fn exit() {
|
||||
pub(crate) fn exit() {
|
||||
debug!("Exiting...");
|
||||
std::process::exit(0)
|
||||
}
|
||||
pub fn clear() {
|
||||
|
||||
pub(crate) fn clear() {
|
||||
info!("Clearing screen..., running command");
|
||||
let _result = if cfg!(target_os = "windows") {
|
||||
debug!("target_os is windows");
|
||||
Command::new("cmd").args(["/c", "cls"]).spawn()
|
||||
} else {
|
||||
debug!("target_os was unix");
|
||||
debug!("target_os is unix");
|
||||
// "clear" or "tput reset"
|
||||
Command::new("tput").arg("reset").spawn()
|
||||
};
|
||||
}
|
||||
pub fn cmds() {
|
||||
|
||||
pub(crate) fn help() {
|
||||
println!("Commands:");
|
||||
for cmd in COMMAND_LIST.commands.read().iter() {
|
||||
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 colored::Colorize;
|
||||
use log2::info;
|
||||
|
||||
pub mod core;
|
||||
|
||||
pub fn print_splash() {
|
||||
println!(
|
||||
r#"
|
||||
&&&&&&&&&&&
|
||||
&&&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&&&&&&&&&&&&&
|
||||
&& &&&&&&&&&
|
||||
&& &&&&&&&&&
|
||||
&&&&&&&&&&&& &&&&&&&&&&&
|
||||
&&&&&&&&&&&&& &&&&&&&&&&&&
|
||||
&&&&&&&&&&&&& &&&&&&&&&&&&&
|
||||
&&&&&&&&&&&& &&&&&&&&&&&&&
|
||||
&&&&&&&&&&& &&&&&&&&&&&&
|
||||
&&&&&&&&& &&
|
||||
&&&&&&&&& &&
|
||||
&&&&&&&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&&&
|
||||
|
||||
Version: {}
|
||||
"#,
|
||||
env!("CARGO_PKG_VERSION").yellow().italic().underline()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let _log2 = log2::open("z.log").tee(true).level("debug").start();
|
||||
info!("Initalizing Engine");
|
||||
let shell_thread = tokio::task::spawn(async {
|
||||
info!("Shell thread started");
|
||||
core::repl::handle_repl().await;
|
||||
core::repl::repl::handle_repl().await;
|
||||
});
|
||||
|
||||
core::splash::print_splash();
|
||||
print_splash();
|
||||
info!("Engine Initalized");
|
||||
core::init_renderer()?;
|
||||
shell_thread.await?;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue