From 1e7d513f26fce88dfb94fe4a4cd30fca0f8b2b45 Mon Sep 17 00:00:00 2001 From: zxq5 Date: Tue, 18 Feb 2025 20:05:54 +0000 Subject: [PATCH] updating apps to work with new API, working on new terminal app. a lot of stuff is broken rn :/ --- src/main.rs | 14 +- src/system/kernel/render.rs | 18 ++- src/system/std/application.rs | 5 +- src/system/std/render.rs | 66 +++++++- src/user/bin/apps/calc/calc.rs | 7 +- src/user/bin/apps/editor.rs | 20 ++- src/user/bin/apps/grapher.rs | 12 +- src/user/bin/apps/tasks.rs | 6 +- src/user/bin/apps/zxqsh.rs | 199 +++++++++++++++++++----- src/user/bin/games/asteroids.rs | 8 +- src/user/bin/games/connect4.rs | 9 +- src/user/bin/games/gameoflife.rs | 21 ++- src/user/bin/games/paper_rs/game.rs | 8 +- src/user/bin/games/pong.rs | 8 +- src/user/bin/games/snake.rs | 36 +++-- src/user/bin/mod.rs | 1 - src/user/bin/shell.rs | 64 ++++---- src/user/bin/shellrewrite.rs | 158 ------------------- src/user/bin/utils/crystalfetch.rs | 6 +- src/user/bin/utils/gigachad_detector.rs | 6 +- src/user/bin/utils/rickroll.rs | 6 +- 21 files changed, 369 insertions(+), 309 deletions(-) delete mode 100644 src/user/bin/shellrewrite.rs diff --git a/src/main.rs b/src/main.rs index 691298c..4e2e82d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,10 +4,15 @@ #![test_runner(CrystalOS::test_runner)] #![reexport_test_harness_main = "test_main"] +use alloc::vec::Vec; use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; use CrystalOS::std::tasks::{Executor, Task}; use CrystalOS::{printerr, serial_println, std::syscall}; +use CrystalOS::apps::zxqsh::ZxqSH; +use CrystalOS::std::application::Application; +use CrystalOS::std::render::Window; + extern crate alloc; use CrystalOS::user::bin::shell; @@ -37,9 +42,16 @@ fn main(boot_info: &'static BootInfo) -> ! { // runs the 'mainloop' of the OS; let mut executor = Executor::new(); - executor.spawn(Task::new(shell::command_handler())); + // executor.spawn(Task::new(shell::command_handler())); + executor.spawn(Task::new(start_shell())); + loop { executor.try_run(); } } +async fn start_shell() { + let window = Window::new(); + let mut shell = ZxqSH::new(Some(window)).unwrap(); + shell.run(Vec::new()).await.unwrap(); +} \ No newline at end of file diff --git a/src/system/kernel/render.rs b/src/system/kernel/render.rs index 678fa1d..4861417 100644 --- a/src/system/kernel/render.rs +++ b/src/system/kernel/render.rs @@ -1,3 +1,4 @@ +use alloc::string::String; use core::fmt; use lazy_static::lazy_static; use spin::Mutex; @@ -5,6 +6,7 @@ use volatile::Volatile; use alloc::vec; use alloc::vec::Vec; +use crate::serial_println; #[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -62,6 +64,14 @@ impl ScreenChar { colour: ColorCode::new(Color::White, Color::Black), } } + + pub fn blank() -> ScreenChar { + ScreenChar { + character: ' ' as u8, + colour: ColorCode::new(Color::White, Color::Black), + } + } + pub fn white(mut character: u8) -> ScreenChar { if let Some(c) = special_char(character as char) { character = c; @@ -113,15 +123,17 @@ lazy_static! { impl Renderer { // EXTERNAL API : for use by standard library and other parts of the kernel pub fn render_frame(&mut self, mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer + for (i, row) in frame.iter_mut().enumerate() { for (j, col) in row.iter_mut().enumerate() { + if col.character == 0u8 { continue; } if let Some(c) = special_char(col.character as char) { col.character = c as u8; } + + self.app_buffer[i][j] = *col; } } - - self.app_buffer = frame; self.internal_render(); } @@ -361,4 +373,4 @@ pub fn write(args: fmt::Arguments, cols: (Color, Color)) { writer.write_fmt(args).unwrap(); writer.reset_colour(); }) -} \ No newline at end of file +} diff --git a/src/system/std/application.rs b/src/system/std/application.rs index 9c37a2a..8dcbde9 100644 --- a/src/system/std/application.rs +++ b/src/system/std/application.rs @@ -5,9 +5,9 @@ use super::render::Window; #[async_trait] pub trait Application { - fn new() -> Self; + fn new(window: Option) -> Result where Self: Sized; - async fn run(&mut self, _window: Option, _args: Vec) -> Result<(), Error> { + async fn run(&mut self, _args: Vec) -> Result<(), Error> { Ok(()) } } @@ -18,6 +18,7 @@ pub enum Error { CommandFailed(String), ApplicationError(String), EmptyCommand, + NoWindow, } pub enum Exit { diff --git a/src/system/std/render.rs b/src/system/std/render.rs index 1ef9bb7..046ae83 100644 --- a/src/system/std/render.rs +++ b/src/system/std/render.rs @@ -39,7 +39,7 @@ impl Window { x: 0, y: 0, bordered: true, - open: true, + open: false, title: String::new(), } } @@ -54,6 +54,10 @@ impl Window { Ok(()) } + pub fn is_open(&self) -> bool { + self.open + } + pub fn dimensions(&self) -> Dimensions { Dimensions::new(self.width, self.height) } @@ -86,18 +90,23 @@ impl Window { } if self.bordered { - self.outline(&mut frame)?; + self.outline(&mut frame); } RENDERER.lock().render_frame(frame); Ok(()) } + fn clear(&self) { + let mut frame = Frame::from_window(self); + self.render(&frame).unwrap() + } + pub fn move_cursor(&self, x: i32, y: i32) -> Result<(), RenderError> { RENDERER.lock().cursor_position((x + self.x as i32) as u8, (y + self.y as i32) as u8) } - fn outline(&self, frame: &mut [[ScreenChar; 80]; 25]) -> Result<(), RenderError> { + fn outline(&self, frame: &mut [[ScreenChar; 80]; 25]) { // draws the sides of the container // Calculate the dimensions let dimensions = self.dimensions(); @@ -162,13 +171,33 @@ impl Window { frame[y as usize][x as usize] = ColouredChar::new(c).as_screen_char(); } } - Ok(()) + } + + pub fn close(&mut self) { + self.open = false; + + let mut frame = Frame::from_window(self); + frame.position.x = (frame.position.x as isize - 1).max(0).min(BUFFER_WIDTH as isize - 1) as usize; + frame.position.y = (frame.position.y as isize - 1).max(0).min(BUFFER_HEIGHT as isize - 1) as usize; + frame.dimensions.x = (frame.dimensions.x as isize + 2).max(2).min(BUFFER_WIDTH as isize + frame.position.x as isize) as usize; + frame.dimensions.y = (frame.dimensions.y as isize + 2).max(2).min(BUFFER_HEIGHT as isize + frame.position.y as isize) as usize; + frame.frame = vec![vec![ColouredChar::blank(); frame.dimensions.x]; frame.dimensions.y]; + let mut newf: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT]; + + for (i, row) in frame.frame.iter().enumerate() { + for (j, col) in row.iter().enumerate() { + newf[i + frame.position.y][j + frame.position.x] = col.as_screen_char(); + }; + } + RENDERER.lock().render_frame(newf); } } impl Drop for Window { fn drop(&mut self) { - RENDERER.lock().terminal_mode(); + if self.open { + self.close() + } } } @@ -188,7 +217,14 @@ impl ColouredChar { colour: ColorCode::new(Color::White, Color::Black), } } - pub fn null() -> ColouredChar { + + pub fn null () -> ColouredChar { + ColouredChar { + character: 0u8 as char, + colour: ColorCode::new(Color::Black, Color::Black), + } + } + pub fn blank() -> ColouredChar { ColouredChar { character: ' ', colour: ColorCode::new(Color::White, Color::Black), @@ -206,6 +242,7 @@ impl ColouredChar { colour: self.colour, } } + } #[derive(Copy, Clone, Debug)] @@ -260,7 +297,7 @@ impl Frame { Ok(Frame { position, dimensions, - frame: vec![vec![ColouredChar::null(); dimensions.x]; dimensions.y], + frame: vec![vec![ColouredChar::blank(); dimensions.x]; dimensions.y], }) } @@ -268,7 +305,7 @@ impl Frame { Frame { dimensions: Dimensions::new(window.width as usize, window.height as usize), position: Position::new(window.x as usize, window.y as usize), - frame: vec![vec![ColouredChar::null(); window.width as usize]; window.height as usize], + frame: vec![vec![ColouredChar::blank(); window.width as usize]; window.height as usize], } } @@ -367,6 +404,19 @@ impl Frame { } } +impl core::fmt::Display for Frame { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + for row in &self.frame { + for col in row { + if col.character as u8 == 0u8 { write!(f, "~")?; continue; } + if col.character == ' ' { write!(f, "@")?; continue; } + write!(f, "{}", col.character)?; + } + writeln!(f)?; + } + Ok(()) + } +} impl core::ops::Index for Frame { type Output = Vec; fn index(&self, index: usize) -> &Self::Output { diff --git a/src/user/bin/apps/calc/calc.rs b/src/user/bin/apps/calc/calc.rs index ffc4c97..57d79b0 100755 --- a/src/user/bin/apps/calc/calc.rs +++ b/src/user/bin/apps/calc/calc.rs @@ -6,6 +6,7 @@ use crate::std::render::Window; use crate::{println, print, mknode, std}; use async_trait::async_trait; +use crate::std::application; use crate::std::application::{ Application, Error as ShellError @@ -358,11 +359,11 @@ pub struct Calculator {} #[async_trait] impl Application for Calculator { - fn new() -> Self { - Self {} + fn new(window: Option) -> Result { + Ok(Calculator {}) } - async fn run(&mut self, window: Option, args: Vec) -> Result<(), ShellError> { + async fn run(&mut self, args: Vec) -> Result<(), ShellError> { if args.len() == 0 { loop { print!("enter equation > "); diff --git a/src/user/bin/apps/editor.rs b/src/user/bin/apps/editor.rs index 5fc6306..a63ad7c 100644 --- a/src/user/bin/apps/editor.rs +++ b/src/user/bin/apps/editor.rs @@ -143,8 +143,10 @@ impl ToString for Editor { #[async_trait] impl Application for Editor { - fn new() -> Editor { - Editor { + fn new(window: Option) -> Result { + let window = if let Some(window) = window { window } else { return Err(application::Error::NoWindow) }; + + Ok(Editor { buffer: Vec::new(), cursor_pos: Position::zero(), offset_pos: Position::zero(), @@ -152,18 +154,14 @@ impl Application for Editor { mode: Mode::Normal, unsaved: false, lineno_width: 0, - window: Window::new(), - } + window, + }) } - async fn run(&mut self, window: Option, args: Vec) -> Result<(), application::Error> { + async fn run(&mut self, args: Vec) -> Result<(), application::Error> { - if let Some(w) = window { - self.window = w; - } - - self.window.set_dimensions(60, 23); - self.window.set_position(10, 1); + self.window.set_dimensions(60, 15); + self.window.set_position(10, 3); self.window.set_title("Editor"); self.window.open(); diff --git a/src/user/bin/apps/grapher.rs b/src/user/bin/apps/grapher.rs index 1951663..f87d3d1 100644 --- a/src/user/bin/apps/grapher.rs +++ b/src/user/bin/apps/grapher.rs @@ -43,13 +43,14 @@ struct PointI64 { #[async_trait] impl Application for Grapher { - fn new() -> Self { - Self { + fn new(window: Option) -> Result { + Ok(Self { points: Vec::new(), frame: Frame::new(Position::new(1, 1), Dimensions::new(78, 22)).unwrap() - } + }) } - async fn run(&mut self, window: Option, args: Vec) -> Result<(), Error> { + + async fn run(&mut self, args: Vec) -> Result<(), Error> { let _d = Display::borrow(); self.frame.frame = vec![vec![ColouredChar::new(' '); self.frame.dimensions.x]; self.frame.dimensions.y]; @@ -71,6 +72,7 @@ impl Application for Grapher { return Ok(()); } + else { let mut container = CgContainer::new( Position::new(0, 0), @@ -149,7 +151,7 @@ impl Grapher { fn graph_equation(&mut self, equation: String, offsets: (i64, i64)) { - let cal = calc::Calculator::new(); + let cal = calc::Calculator::new(None).unwrap(); let ast = cal.get_expr(equation.chars().map(|c| { match c { 'e' => format!("({})", E), diff --git a/src/user/bin/apps/tasks.rs b/src/user/bin/apps/tasks.rs index 06bee49..0a161b0 100644 --- a/src/user/bin/apps/tasks.rs +++ b/src/user/bin/apps/tasks.rs @@ -26,9 +26,11 @@ pub struct Tasks; #[async_trait] impl Application for Tasks { - fn new() -> Self { Self {} } + fn new(window: Option) -> Result { + Ok(Tasks) + } - async fn run(&mut self, window: Option, args: Vec) -> Result<(), Error> { + async fn run(&mut self, args: Vec) -> Result<(), Error> { if args[0].clone() == String::from("add") { diff --git a/src/user/bin/apps/zxqsh.rs b/src/user/bin/apps/zxqsh.rs index 38f740d..e00923c 100644 --- a/src/user/bin/apps/zxqsh.rs +++ b/src/user/bin/apps/zxqsh.rs @@ -1,4 +1,5 @@ -use alloc::{string::String, vec::Vec, boxed::Box}; +use alloc::{string::String, vec::Vec, boxed::Box, format}; +use alloc::string::ToString; use core::any::Any; use crate::std::{application::{Application, Error}, render::Window}; @@ -10,9 +11,10 @@ use crate::apps::grapher::Grapher; use crate::apps::tasks::Tasks; use crate::games::gameoflife::GameOfLife; use crate::games::paper_rs::GameBoard; -use crate::{games, println, utils}; -use crate::std::io::{Display, Serial}; -use crate::std::render::{ColouredChar, Frame, RenderError}; +use crate::{games, println, serial_println, utils}; +use crate::std::application::Error::ApplicationError; +use crate::std::io::{Color, ColorCode, Display, KeyStroke, Serial, Stdin}; +use crate::std::render::{ColouredChar, Frame, Position, RenderError}; use crate::std::time::timer; use crate::user::lib::libgui::cg_core::CgComponent; use crate::utils::crystalfetch::CrystalFetch; @@ -23,24 +25,44 @@ pub struct ZxqSH { history: Vec, history_idx: usize, - row_pos: usize, - col_pos: usize, - window: Window, - buffer: Vec>, - buffer_width: usize, + + // the buffer is a vec of coloured characters + // we use a 1d vec so that the terminal can be resized. + buffer: Vec, } #[async_trait] impl Application for ZxqSH { - fn new() -> Self { - todo!() + fn new(window: Option) -> Result { + match window { + Some(window) => { + Ok(ZxqSH { + history: Vec::new(), + history_idx: 0, + window, + buffer: Vec::new(), + }) + } + None => Err(Error::NoWindow), + } } - async fn run(&mut self, window: Option, _args: Vec) -> Result<(), Error> { + async fn run(&mut self, _args: Vec) -> Result<(), Error> { + self.window.set_dimensions(78, 23); + self.window.set_position(1, 1); + self.window.set_title("Terminal"); + self.window.open(); + loop { - if let Ok(exit) = self.next().await { - if exit { return Ok(()) } + match self.next().await { + Err(e) => { + self.write(format!("Error: {:?}", e), Color::Yellow); + return Err(e); + }, + Ok(exit) => { + if exit { return Ok(()) } + } } } } @@ -52,20 +74,95 @@ impl ZxqSH { // update cycle for the shell // TODO: prompt - let command = String::new(); - + let mut command = self.input().await; // TODO: exit if necessary // TODO: execute command - self.execute(command, Vec::new()).await; - // return + if let Err(e) = self.execute(command, Vec::new()).await { + match e { + Error::UnknownCommand(e) => { + self.write("Unknown command\n".to_string(), Color::Yellow); + } + _ => { + self.write(format!("Error: {:?}\n", e), Color::Yellow); + } + } + } Ok(false) } - async fn write_char(&mut self, ch: char) { - self.buffer[self.row_pos][self.col_pos] = ColouredChar::new(ch); + fn write(&mut self, string: String, color: Color) { + for ch in string.chars() { + self.write_char(ch, color); + } + } + fn write_char(&mut self, ch: char, color: Color) { + self.buffer.push(ColouredChar::coloured(ch, ColorCode::new(color, Color::Black))); + while self.buffer.len() > 100000 { + self.buffer.remove(0); + } + + if let Ok(frame) = self.render() { + self.window.render(&frame).unwrap(); + } + } + + fn backspace(&mut self) { + let _ = self.buffer.pop(); + if let Ok(frame) = self.render() { + self.window.render(&frame).unwrap(); + } + } + + async fn input(&mut self) -> String { + let mut string = String::new(); + self.write("ZxqS> ".to_string(), Color::Cyan); + + loop { + let ch = Stdin::keystroke().await; + match ch { + KeyStroke::Char(c) => { + match c { + '\x08' => { + if string.len() == 0 { continue; } + string.pop(); + self.backspace() + }, + '\n' => { + self.write_char(c, Color::White); + break + }, + _ => { + self.write_char(c, Color::White); + string.push(c) + } + } + } + _ => {} + } + } + + string + } + + fn get_col(&self) -> usize { + let term_width = self.window.dimensions().x as isize; + let mut col = self.buffer.iter().rev().take_while(|c| c.character != '\n').count() as isize; + + while col - term_width >= 0 { + col -= term_width; + } + + col as usize + } + + fn lines(&self) -> Vec> { + self.buffer + .split(|c| c.character == '\n') + .map(|line| line.to_vec()) + .collect() } async fn execute(&self, cmd: String, args: Vec) -> Result<(), Error> { @@ -73,11 +170,11 @@ impl ZxqSH { let window = Window::new(); match cmd.as_str() { - "calculate" | "calc" | "solve" => Calculator::new().run(Some(window), args).await?, - "games/connect4" => crate::user::bin::games::connect4::Game::new().run(Some(window), args).await?, - "rickroll" => Rickroll::new().run(Some(window), args).await?, - "crystalfetch" => CrystalFetch::new().run(Some(window), args).await?, - "tasks" => Tasks::new().run(Some(window), args).await?, + "calculate" | "calc" | "solve" => Calculator::new(Some(window)).expect("couldn't open window").run(args).await?, + "games/connect4" => crate::user::bin::games::connect4::Game::new(Some(window)).expect("couldn't open window").run(args).await?, + "rickroll" => Rickroll::new(Some(window)).expect("couldn't open window").run(args).await?, + "crystalfetch" => CrystalFetch::new(Some(window)).expect("couldn't open window").run(args).await?, + "tasks" => Tasks::new(Some(window)).expect("couldn't open window").run(args).await?, "VGA" => { use vga::colors::Color16; use vga::writers::{GraphicsWriter, Graphics640x480x16}; @@ -86,19 +183,18 @@ impl ZxqSH { mode.clear_screen(Color16::Black); mode.draw_line((80, 60), (120, 420), Color16::Cyan); }, - "graph" => Grapher::new().run(Some(window), args).await?, - "games/snake" => games::snake::Game::new().run(Some(window), args).await?, - "games/asteroids" => games::asteroids::Game::new().run(Some(window), args).await?, - "games/pong" => games::pong::Game::new().run(Some(window), args).await?, - "games/paper.rs" => games::paper_rs::GameBoard::new().run(Some(window), args).await?, + "graph" => Grapher::new(Some(window)).expect("couldn't open window").run(args).await?, + "games/snake" => games::snake::Game::new(Some(window)).expect("couldn't open window").run(args).await?, + "games/asteroids" => games::asteroids::Game::new(Some(window)).expect("couldn't open window").run(args).await?, + "games/pong" => games::pong::Game::new(Some(window)).expect("couldn't open window").run(args).await?, + "games/paper.rs" => games::paper_rs::GameBoard::new(Some(window)).expect("couldn't open window").run(args).await?, "serial" => println!("{}", Serial::reply_char('e')), - "games/gameoflife" => GameOfLife::new().run(Some(window), Vec::new()).await?, + "games/gameoflife" => GameOfLife::new(Some(window)).expect("couldn't open window").run(Vec::new()).await?, "games/tetris" => { - // games::tetris::TetrisEngine::new().run(Vec::new()).await?; + // games::tetris::TetrisEngine::new().expect("couldn't open window").run(Vec::new()).await?; } - "gigachad?" => utils::gigachad_detector::GigachadDetector::new().run(Some(window), args).await?, - "editor" => Editor::new().run(Some(window), args).await?, - + "gigachad?" => utils::gigachad_detector::GigachadDetector::new(Some(window)).expect("couldn't open window").run(args).await?, + "editor" => Editor::new(Some(window)).expect("couldn't open window").run(args).await?, // direct OS functions (not applications) "echo" => { println!( @@ -116,6 +212,10 @@ impl ZxqSH { _ => return Err(Error::UnknownCommand(cmd)) }; + if let Ok(frame) = self.render() { + self.window.render(&frame).unwrap(); + } + Ok(()) } } @@ -126,17 +226,34 @@ impl CgComponent for ZxqSH { let term_height = self.window.dimensions().y; let term_width = self.window.dimensions().x; - let buffer_width = self.buffer_width; - let buffer_height = self.buffer.len(); - self.window.move_cursor(self.col_pos as i32, term_height as i32)?; + self.window.move_cursor(self.get_col() as i32, term_height as i32 - 1)?; // render the contents of the terminal to a frame - for (i, row) in self.buffer[buffer_height - term_height..buffer_height].iter().enumerate() { - for (j, col) in row.iter().enumerate().take(term_width) { - frame[i][j] = *col; + + let mut line = term_height - 1; + let mut col = self.get_col(); + let buff = self.lines(); + let mut lines = buff.iter(); + + for line_chars in lines.rev() { + col = line_chars.len() % term_width; + + for c in line_chars.iter().rev() { + if c.character == '\n' { continue; } + frame.write(Position::new(col, line), c.clone())?; + + if col <= 0 { + line -= 1; + col = term_width; + } + + col -= 1; } + + line -= 1; } + Ok(frame) } diff --git a/src/user/bin/games/asteroids.rs b/src/user/bin/games/asteroids.rs index 7f3448d..8364eff 100644 --- a/src/user/bin/games/asteroids.rs +++ b/src/user/bin/games/asteroids.rs @@ -41,8 +41,8 @@ pub struct Game { #[async_trait] impl Application for Game { - fn new() -> Self { - Self { + fn new(window: Option) -> Result { + Ok(Self { player: Player::new(), enemies: Vec::new(), score: 0, @@ -50,9 +50,9 @@ impl Application for Game { difficulty_idx: 1, gamespeed: 1.0, timer: GameTimer::new(), - } + }) } - async fn run(&mut self, window: Option, _args: Vec) -> Result<(), Error> { + async fn run(&mut self, _args: Vec) -> Result<(), Error> { let _d = Display::borrow(); let mut container_data = diff --git a/src/user/bin/games/connect4.rs b/src/user/bin/games/connect4.rs index 08e48c9..6a348e4 100644 --- a/src/user/bin/games/connect4.rs +++ b/src/user/bin/games/connect4.rs @@ -21,19 +21,18 @@ pub enum Cell { #[async_trait] impl Application for Game { - fn new() -> Self { - Game { + fn new(window: Option) -> Result { + Ok(Game { board: [[Cell::Empty; 7]; 6], turn: 1, vs_ai: false, game_over: false, winner: None, - } + }) } - async fn run(&mut self, window: Option, _: Vec) -> Result<(), Error> { + async fn run(&mut self, _: Vec) -> Result<(), Error> { let _display = Display::borrow(); - self.get_next_mode().await; // Main game loop diff --git a/src/user/bin/games/gameoflife.rs b/src/user/bin/games/gameoflife.rs index edf0310..5f37431 100644 --- a/src/user/bin/games/gameoflife.rs +++ b/src/user/bin/games/gameoflife.rs @@ -1,9 +1,10 @@ use alloc::string::String; -use alloc::vec; +use alloc::{format, vec}; use alloc::vec::Vec; use alloc::boxed::Box; use crate::std::application::{Application, Error}; use async_trait::async_trait; +use futures_util::future::err; use crate::std::render::{ColouredChar, Dimensions, Frame, Position, RenderError, Window}; use crate::std::io::{KeyStroke, Stdin, Color, ColorCode, Display}; use crate::std::time::wait; @@ -16,12 +17,18 @@ const LOOP_SPEED: f64 = 0.1; #[async_trait] impl Application for GameOfLife { - fn new() -> Self { - Self { - frame: Frame::new(Position::new(0, 0), Dimensions::new(80, 25)).unwrap() + fn new(window: Option) -> Result { + let mut frame: Frame; + if let Some(window) = window { + frame = Frame::new(Position::new(0, 0), Dimensions::new(80, 25)).unwrap(); + frame.dimensions = window.dimensions(); + frame.position = window.position(); + Ok(Self { frame }) + } else { + return Err(Error::NoWindow); } } - async fn run(&mut self, window: Option, _args: Vec) -> Result<(), Error> { + async fn run(&mut self, _args: Vec) -> Result<(), Error> { // setup: let _d = Display::borrow(); @@ -100,12 +107,12 @@ impl GameOfLife { if self.frame[y as usize][x as usize] == ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black)) { return ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black)); } else { - return ColouredChar::null(); + return ColouredChar::blank(); } } else if alive == 3 { ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black)) } else { - ColouredChar::null() + ColouredChar::blank() } } diff --git a/src/user/bin/games/paper_rs/game.rs b/src/user/bin/games/paper_rs/game.rs index 74c3a35..3390ca9 100644 --- a/src/user/bin/games/paper_rs/game.rs +++ b/src/user/bin/games/paper_rs/game.rs @@ -33,8 +33,8 @@ pub struct GameBoard { #[async_trait] impl Application for GameBoard { - fn new() -> GameBoard { - GameBoard { + fn new(window: Option) -> Result { + Ok(GameBoard { board: [[Cell::Empty; 80]; 25], players: [ Player::new(0, (10, 10), false), @@ -46,10 +46,10 @@ impl Application for GameBoard { ], max_territory: 0, current_territory: 0, - } + }) } - async fn run(&mut self, window: Option, _args: Vec) -> Result<(), Error> { + async fn run(&mut self, _args: Vec) -> Result<(), Error> { let _display = Display::borrow(); 'outer: loop { diff --git a/src/user/bin/games/pong.rs b/src/user/bin/games/pong.rs index 2038736..51c2a73 100644 --- a/src/user/bin/games/pong.rs +++ b/src/user/bin/games/pong.rs @@ -17,15 +17,15 @@ pub(crate) struct Game { #[async_trait] impl Application for Game { - fn new() -> Self { - Game { + fn new(window: Option) -> Result { + Ok(Game { ball: Ball::new(), player1: Player::new(1), player2: Player::new(78), - } + }) } - async fn run(&mut self, window: Option, _: Vec) -> Result<(), Error> { + async fn run(&mut self, _: Vec) -> Result<(), Error> { let _d = Display::borrow(); let mut update_time = Timer::new(0.1); diff --git a/src/user/bin/games/snake.rs b/src/user/bin/games/snake.rs index 3962f6b..9512617 100644 --- a/src/user/bin/games/snake.rs +++ b/src/user/bin/games/snake.rs @@ -1,4 +1,4 @@ -use alloc::string::String; +use alloc::string::{String, ToString}; use alloc::{format, vec, vec::Vec, boxed::Box}; use async_trait::async_trait; use crate::std::io::{Color, Display, KeyStroke, Stdin}; @@ -30,22 +30,34 @@ pub struct Game { pois: Vec, score: u8, gamemode: Gamemode, + window: Window, } #[async_trait] impl Application for Game { - fn new() -> Self { - Self { + fn new(window: Option) -> Result { + let window = match window { + Some(w) => w, + None => return Err(Error::NoWindow), + }; + + Ok(Self { snakes: Vec::new(), pois: Vec::new(), score: 0, - gamemode: Gamemode::Uninitialised, - } + gamemode: Gamemode::Uninitialised, + window, + }) } - async fn run(&mut self, window: Option, args: Vec) -> Result<(), Error> { + async fn run(&mut self, args: Vec) -> Result<(), Error> { + self.window.set_title("snake game"); + self.window.set_dimensions(78, 23); + self.window.set_position(1, 1); + self.window.open(); + let _settings = [0, 0, 0]; // ai_count, snake_len, poi_count @@ -75,7 +87,6 @@ impl Application for Game { self.prepare(); // switch OS to application mode - let _d = Display::borrow(); // render the initial state of the screen. self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?; // run the game @@ -154,7 +165,7 @@ impl Game { } fn new_poi(&mut self) { - self.pois.push(Position { x: Random::int(3, 76) as i64, y: Random::int(3, 21) as i64 }); + self.pois.push(Position { x: Random::int(3, self.window.dimensions().x - 4) as i64, y: Random::int(3, self.window.dimensions().y - 4) as i64 }); } fn replace_poi(&mut self, poi: &Position) { @@ -164,7 +175,7 @@ impl Game { fn render(&mut self) -> Result<(), RenderError> { - let mut frame = Frame::new(render::Position::new(0, 0), Dimensions::new(80, 25))?; + let mut frame = Frame::new(render::Position::new(0, 0), self.window.dimensions())?; let mut curr_colour = ColorCode::new(Color::LightBlue, Color::Black); for s in self.snakes.clone() { @@ -182,15 +193,14 @@ impl Game { }); let literal = format!("snake go brr score: {}", self.score); - let msg = Game::centre_text(80, literal); + let msg = Game::centre_text(self.window.dimensions().x, literal); msg.chars().enumerate().for_each(|(i, c)| { if c != ' ' { frame[1][i] = ColouredChar::coloured(c, ColorCode::new(Color::LightGreen, Color::Black)) } }); - frame.write_to_screen()?; - + self.window.render(&frame)?; Ok(()) } @@ -211,7 +221,7 @@ impl Game { frame[12] = Game::centre_text(80, String::from(format!("ur score was {}", self.score))).chars().map(|c| ColouredChar::coloured(c, ColorCode::new(Color::LightGreen, Color::Black))).collect(); frame[14] = Game::centre_text(80, String::from("L bozo")).chars().map(|c| ColouredChar::coloured(c, ColorCode::new(Color::Red, Color::Black))).collect(); - frame.write_to_screen()?; + self.window.render(&frame)?; Ok(()) } } diff --git a/src/user/bin/mod.rs b/src/user/bin/mod.rs index 20c0d95..753ee30 100644 --- a/src/user/bin/mod.rs +++ b/src/user/bin/mod.rs @@ -2,4 +2,3 @@ pub mod apps; pub mod games; pub mod utils; pub mod shell; -pub mod shellrewrite; \ No newline at end of file diff --git a/src/user/bin/shell.rs b/src/user/bin/shell.rs index 0849961..5b37aaa 100644 --- a/src/user/bin/shell.rs +++ b/src/user/bin/shell.rs @@ -48,6 +48,7 @@ use crate::{ } }, }; +use crate::apps::zxqsh::ZxqSH; lazy_static! { pub static ref CMD: Mutex = Mutex::new(CommandHandler::new()); @@ -66,11 +67,11 @@ pub async fn eventloop() { let window = Window::new(); - let mut fetch = CrystalFetch::new(); + let mut fetch = CrystalFetch::new(Some(window)).unwrap(); let string = String::from(" "); let mut vec: Vec = Vec::new(); vec.push(string); - fetch.run(Some(window), vec).await.unwrap(); + fetch.run(vec).await.unwrap(); CMD.lock().prompt(); @@ -103,6 +104,9 @@ fn handle_error(e: Error) { Error::CommandFailed(e) => { printerr!("command failed:\n{}", e); }, + Error::NoWindow => { + printerr!("no window"); + } } } @@ -125,27 +129,27 @@ async fn exec() -> Result<(), Error> { match cmd.as_str() { "calculate" | "calc" | "solve" => { - let mut cmd = Calculator::new(); - cmd.run(Some(window), args).await?; + let mut cmd = Calculator::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "games/connect4" => { - let mut cmd = Connect4Game::new(); - cmd.run(Some(window), args).await?; + let mut cmd = Connect4Game::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "rickroll" => { - let mut cmd = Rickroll::new(); - cmd.run(Some(window), args).await?; + let mut cmd = Rickroll::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "crystalfetch" => { - let mut cmd = CrystalFetch::new(); - cmd.run(Some(window), args).await?; + let mut cmd = CrystalFetch::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "tasks" => { - let mut cmd = Tasks::new(); - cmd.run(Some(window), args).await?; + let mut cmd = Tasks::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "VGA" => { use vga::colors::Color16; @@ -157,45 +161,49 @@ async fn exec() -> Result<(), Error> { mode.draw_line((80, 60), (120, 420), Color16::Cyan); } "graph" => { - Grapher::new().run(Some(window), args).await?; + Grapher::new(Some(window)).expect("couldn't open window").run(args).await?; } "games/snake" => { - SnakeGame::new().run(Some(window), args).await?; + SnakeGame::new(Some(window)).expect("couldn't open window").run(args).await?; } "games/asteroids" => { - let mut asteroid_game = AsteroidsGame::new(); - asteroid_game.run(Some(window), args).await?; + let mut cmd = AsteroidsGame::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "games/pong" => { - PongGame::new().run(Some(window), args).await?; + let mut cmd = PongGame::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "games/paper.rs" => { - let mut game = GameBoard::new(); - game.run(Some(window), args).await?; + let mut cmd = GameBoard::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "serial" => { let c = Serial::reply_char('e'); println!("{}", c); } "games/gameoflife" => { - let mut game = GameOfLife::new(); - game.run(Some(window), Vec::new()).await?; + let mut cmd = GameOfLife::new(Some(window)).expect("couldn't open window"); + cmd.run(Vec::new()).await?; } "games/tetris" => { - // let mut game = TetrisEngine::new(); - // game.run(Vec::new()).await?; + // let mut cmd = TetrisEngine::new(Some(window)).expect("couldn't open window"); + // cmd.run(Vec::new()).await?; + }, + "shell" => { + let mut cmd = ZxqSH::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "gigachad?" => { - let mut detector = GigachadDetector::new(); - detector.run(Some(window), args).await?; + let mut cmd = GigachadDetector::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } "editor" => { - let mut editor = Editor::new(); - editor.run(Some(window), args).await?; + let mut cmd = Editor::new(Some(window)).expect("couldn't open window"); + cmd.run(args).await?; } - // direct OS functions (not applications) "echo" => { println!( diff --git a/src/user/bin/shellrewrite.rs b/src/user/bin/shellrewrite.rs deleted file mode 100644 index 95e542b..0000000 --- a/src/user/bin/shellrewrite.rs +++ /dev/null @@ -1,158 +0,0 @@ -// // importing libraries -// 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::Vec}; - -// use crate::{ -// kernel::tasks::{executor::Executor, Task}, -// std::application::{Application, Error}, -// std::io::{print, println, Stdin, Screen}, -// user::bin::*, -// }; -// use crate::std::io::{Color, write}; -// use crate::user::bin::gigachad_detector::GigachadDetector; - -// use super::*; - -// // [ CRYSTAL SHELL ] -// // the purpose of this module is to provide a basic unix shell like experience for the user -// // to interact with the OS -// // this is a rewrite of my original shell. -// // this shell should support: -// // - browsing the virtual filesystem -// // - executing programs -// // - basic arithmetic -// // - chained execution ( multiple commands linked together) eg: '5 + 5 | echo' which calculates -// // the result of 5 + 5 and then sends the result to an echo command which prints it to console - - -// /// starts the shell -// /// this function should be directly called by main.rs or by an init system - - - -// fn run_task(task_name: String, args: Vec) -> Result<(), String> { -// Ok(()) -// } - -// pub async fn userspace() -> Result<(), String> { -// let mut executor = Executor::new(); - -// let mut shell = Shell::new(); -// shell.run(vec![]).await.unwrap(); - -// Ok(()) -// } - -// struct Shell { -// history: Vec, -// } - -// #[async_trait] -// impl Application for Shell { -// fn new() -> Shell { -// Shell { -// history: Vec::new(), -// } -// } -// async fn run(&mut self, _: Vec) -> Result<(), Error> { -// loop { -// self.prompt(); -// let input = Stdin::readline().await; -// let (cmd, args) = self.parse_args(input).unwrap(); -// self.run_cmd(cmd, args).await.unwrap(); -// } -// } -// } - -// impl Shell { -// fn prompt(&mut self) { -// write(format_args!("\n Crystal> "), (Color::Cyan, Color::Black)); -// } - -// // fn exec R>(command: T) -> Result { // this command runs when a shell command is executed -// // Ok(command()) -// // } -// async fn run_cmd(&mut self, cmd: String, args: Vec) -> Result<(), Error> { -// 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?; -// } -// "echo" => { -// println!( -// "Crystal: '{}'", -// " ".join(args) -// ) -// } -// "clear" => { -// Screen::clear(); -// } -// "print" => { -// use crate::std::os::OS; -// let x: String = OS.lock().version.clone(); -// println!("{}", x); -// } -// "snake" => { -// let mut game = snake::Game::new(); -// game.run(Vec::new()).await?; -// } -// "gigachad?" => { -// let mut gigachad_detector = GigachadDetector::new(); -// gigachad_detector.run(args).await?; -// } -// "test_features" => { -// use crate::std::random::Random; -// println!("{}", Random::int(0, 10)); -// } -// _ => { -// return Err(Error::UnknownCommand( -// "command not yet implemented".to_string(), -// )) -// } -// } -// Ok(()) -// } -// fn parse_args(&self, command: String) -> Result<(String, Vec), String> { -// let mut args: Vec = Vec::new(); - -// for arg in command.split(" ").collect::>() { -// 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)) -// } -// } - - diff --git a/src/user/bin/utils/crystalfetch.rs b/src/user/bin/utils/crystalfetch.rs index a1ce825..76d75b6 100644 --- a/src/user/bin/utils/crystalfetch.rs +++ b/src/user/bin/utils/crystalfetch.rs @@ -49,11 +49,11 @@ pub struct CrystalFetch {} #[async_trait] impl Application for CrystalFetch { - fn new() -> Self { - Self {} + fn new(window: Option) -> Result { + Ok(Self {}) } - async fn run(&mut self, window: Option, _args: Vec) -> Result<(), Error> { + async fn run(&mut self, _args: Vec) -> Result<(), Error> { // let ds = Display::borrow(); diff --git a/src/user/bin/utils/gigachad_detector.rs b/src/user/bin/utils/gigachad_detector.rs index 2f76abf..ab39366 100644 --- a/src/user/bin/utils/gigachad_detector.rs +++ b/src/user/bin/utils/gigachad_detector.rs @@ -15,11 +15,11 @@ pub struct GigachadDetector {} #[async_trait] impl Application for GigachadDetector { - fn new() -> Self { - Self {} + fn new(window: Option) -> Result { + Ok(Self {}) } - async fn run(&mut self, window: Option, args: Vec) -> Result<(), Error> { + async fn run(&mut self, args: Vec) -> Result<(), Error> { for arg in args { self.detect_gigachad_by_username(&arg) } diff --git a/src/user/bin/utils/rickroll.rs b/src/user/bin/utils/rickroll.rs index d9bf998..d0b22f1 100644 --- a/src/user/bin/utils/rickroll.rs +++ b/src/user/bin/utils/rickroll.rs @@ -52,11 +52,11 @@ pub struct Rickroll {} #[async_trait] impl Application for Rickroll { - fn new() -> Self { - Self {} + fn new(window: Option) -> Result { + Ok(Self {}) } - async fn run(&mut self, window: Option, _args: Vec) -> Result<(), Error> { + async fn run(&mut self, _args: Vec) -> Result<(), Error> { println!("{}", RICKROLL2); Ok(()) }