use async_trait::async_trait; use lazy_static::lazy_static; use spin::Mutex; use x86_64::instructions::interrupts; use alloc::{ boxed::Box, string::{String, ToString}, vec::Vec, }; use crate::{ print, println, std::application::{Application, Error}, user::bin::*, }; lazy_static! { pub static ref CMD: Mutex = Mutex::new(CommandHandler::new()); } /// boilerplate function /// may provide other interfacing options later on idk. pub async fn command_handler() { eventloop().await; } /// this function starts the shell running, the function will loop repeatedly until the command to shutdown /// TODO: implement shutdown command pub async fn eventloop() { println!("running!"); let mut fetch = crystalfetch::CrystalFetch::new(); let string = String::from(" "); let mut vec: Vec = Vec::new(); vec.push(string); fetch.run(vec).await.unwrap(); CMD.lock().prompt(); loop { let string = crate::std::io::stdin().await; CMD.lock().current.push_str(&string); match exec().await { Ok(_) => { (); } Err(e) => { handle_error(e); } }; CMD.lock().prompt(); } } fn handle_error(e: Error) {} async fn exec() -> Result<(), Error> { let mut current = CMD.lock().current.clone(); CMD.lock().history.history.push(current.clone()); current.pop(); CMD.lock().current = String::new(); let (cmd, args) = match CommandHandler::parse_args(current) { Ok((cmd, args)) => (cmd, args), Err(_) => { return Err(Error::EmptyCommand); } }; match cmd.as_str() { "calculate" | "calc" | "solve" => { let mut cmd = calc::Calculator::new(); cmd.run(args).await?; } "rickroll" => { let mut cmd = rickroll::Rickroll::new(); cmd.run(args).await?; } "crystalfetch" => { let mut cmd = crystalfetch::CrystalFetch::new(); cmd.run(args).await?; } "tasks" => { let mut cmd = tasks::Tasks::new(); cmd.run(args).await?; } "play" => { let mut gameloop = crystal_rpg::init::GameLoop::new(); gameloop.run(args).await?; } // direct OS functions (not applications) "echo" => { println!( "Crystal: '{}'", args.into_iter() .map(|mut s| { s.push_str(" "); s }) .collect::() ) } "clear" => { interrupts::without_interrupts(|| { crate::std::io::clear(); }); } "print" => { use crate::std::os::OS; let x: String = OS.lock().version.clone(); println!("{}", x); } "switch" => { crate::std::io::switch_mode(); } "random" => { use crate::std::random::Random; let vec = Vec::from(["a", "b", "c", "d", "e", "f"]); let sel = Random::selection(vec); println!("{}", sel); } "filesystem" => { use crate::std::io; io::mkfs(); } "test_features" => { use crate::user::lib::libgui; libgui::libgui_core::test_elements(); } _ => { return Err(Error::UnknownCommand( "command not yet implemented".to_string(), )) } }; Ok(()) } pub struct CommandHandler { current: String, history: CmdHistory, } impl CommandHandler { pub fn new() -> Self { let handler = Self { current: String::new(), history: CmdHistory { history: Vec::new(), }, }; handler } pub fn parse_args(command: String) -> Result<(String, Vec), String> { let temp = command.split(" ").collect::>(); let mut args: Vec = Vec::new(); for arg in temp { match arg { "" => {} x => args.push(x.to_string()), } } let cmd: String; if args.len() > 0 { cmd = args[0].clone(); args.remove(0); } else { return Err("command was empty.".to_string()); }; Ok((cmd, args)) } // this function is activated every time the user presses a key on the keyboard // it accesses the queue of keys (a static ref in src/tasks/keyboard.rs) // displays a text prompt for the user to type into. // this is a separate function so that it can be developed as necessary later on // TODO: coloured prompt pub fn prompt(&self) { print!("\n [ Crystal ] >> "); } // this function is run every time the enter key is pressed in the command line mode. // it detects the command that is being run and then executes it, passing the arguments to it. } struct CmdHistory { history: Vec, }