updating apps to work with new API, working on new terminal app. a lot of stuff is broken rn :/

This commit is contained in:
2025-02-18 20:05:54 +00:00
parent 1ace354158
commit 1e7d513f26
21 changed files with 369 additions and 309 deletions
+13 -1
View File
@@ -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();
}
+15 -3
View File
@@ -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();
})
}
}
+3 -2
View File
@@ -5,9 +5,9 @@ use super::render::Window;
#[async_trait]
pub trait Application {
fn new() -> Self;
fn new(window: Option<Window>) -> Result<Self, Error> where Self: Sized;
async fn run(&mut self, _window: Option<Window>, _args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
Ok(())
}
}
@@ -18,6 +18,7 @@ pub enum Error {
CommandFailed(String),
ApplicationError(String),
EmptyCommand,
NoWindow,
}
pub enum Exit {
+58 -8
View File
@@ -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<usize> {
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<usize> for Frame {
type Output = Vec<ColouredChar>;
fn index(&self, index: usize) -> &Self::Output {
+4 -3
View File
@@ -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<Window>) -> Result<Calculator, application::Error> {
Ok(Calculator {})
}
async fn run(&mut self, window: Option<Window>, args: Vec<String>) -> Result<(), ShellError> {
async fn run(&mut self, args: Vec<String>) -> Result<(), ShellError> {
if args.len() == 0 {
loop {
print!("enter equation > ");
+9 -11
View File
@@ -143,8 +143,10 @@ impl ToString for Editor {
#[async_trait]
impl Application for Editor {
fn new() -> Editor {
Editor {
fn new(window: Option<Window>) -> Result<Editor, application::Error> {
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<Window>, args: Vec<String>) -> Result<(), application::Error> {
async fn run(&mut self, args: Vec<String>) -> 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();
+7 -5
View File
@@ -43,13 +43,14 @@ struct PointI64 {
#[async_trait]
impl Application for Grapher {
fn new() -> Self {
Self {
fn new(window: Option<Window>) -> Result<Self, Error> {
Ok(Self {
points: Vec::new(),
frame: Frame::new(Position::new(1, 1), Dimensions::new(78, 22)).unwrap()
}
})
}
async fn run(&mut self, window: Option<Window>, args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, args: Vec<String>) -> 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),
+4 -2
View File
@@ -26,9 +26,11 @@ pub struct Tasks;
#[async_trait]
impl Application for Tasks {
fn new() -> Self { Self {} }
fn new(window: Option<Window>) -> Result<Tasks, Error> {
Ok(Tasks)
}
async fn run(&mut self, window: Option<Window>, args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
if args[0].clone() == String::from("add") {
+158 -41
View File
@@ -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<String>,
history_idx: usize,
row_pos: usize,
col_pos: usize,
window: Window,
buffer: Vec<Vec<ColouredChar>>,
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<ColouredChar>,
}
#[async_trait]
impl Application for ZxqSH {
fn new() -> Self {
todo!()
fn new(window: Option<Window>) -> Result<ZxqSH, Error> {
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<Window>, _args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _args: Vec<String>) -> 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<Vec<ColouredChar>> {
self.buffer
.split(|c| c.character == '\n')
.map(|line| line.to_vec())
.collect()
}
async fn execute(&self, cmd: String, args: Vec<String>) -> 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)
}
+4 -4
View File
@@ -41,8 +41,8 @@ pub struct Game {
#[async_trait]
impl Application for Game {
fn new() -> Self {
Self {
fn new(window: Option<Window>) -> Result<Self, Error> {
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<Window>, _args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
let _d = Display::borrow();
let mut container_data =
+4 -5
View File
@@ -21,19 +21,18 @@ pub enum Cell {
#[async_trait]
impl Application for Game {
fn new() -> Self {
Game {
fn new(window: Option<Window>) -> Result<Self, Error> {
Ok(Game {
board: [[Cell::Empty; 7]; 6],
turn: 1,
vs_ai: false,
game_over: false,
winner: None,
}
})
}
async fn run(&mut self, window: Option<Window>, _: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
let _display = Display::borrow();
self.get_next_mode().await;
// Main game loop
+14 -7
View File
@@ -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<Window>) -> Result<Self, Error> {
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<Window>, _args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _args: Vec<String>) -> 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()
}
}
+4 -4
View File
@@ -33,8 +33,8 @@ pub struct GameBoard {
#[async_trait]
impl Application for GameBoard {
fn new() -> GameBoard {
GameBoard {
fn new(window: Option<Window>) -> Result<Self, Error> {
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<Window>, _args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
let _display = Display::borrow();
'outer: loop {
+4 -4
View File
@@ -17,15 +17,15 @@ pub(crate) struct Game {
#[async_trait]
impl Application for Game {
fn new() -> Self {
Game {
fn new(window: Option<Window>) -> Result<Self, Error> {
Ok(Game {
ball: Ball::new(),
player1: Player::new(1),
player2: Player::new(78),
}
})
}
async fn run(&mut self, window: Option<Window>, _: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
let _d = Display::borrow();
let mut update_time = Timer::new(0.1);
+23 -13
View File
@@ -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<Position>,
score: u8,
gamemode: Gamemode,
window: Window,
}
#[async_trait]
impl Application for Game {
fn new() -> Self {
Self {
fn new(window: Option<Window>) -> Result<Self, Error> {
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<Window>, args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, args: Vec<String>) -> 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(())
}
}
-1
View File
@@ -2,4 +2,3 @@ pub mod apps;
pub mod games;
pub mod utils;
pub mod shell;
pub mod shellrewrite;
+36 -28
View File
@@ -48,6 +48,7 @@ use crate::{
}
},
};
use crate::apps::zxqsh::ZxqSH;
lazy_static! {
pub static ref CMD: Mutex<CommandHandler> = 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<String> = 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!(
-158
View File
@@ -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<String>) -> 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<String>,
// }
// #[async_trait]
// impl Application for Shell {
// fn new() -> Shell {
// Shell {
// history: Vec::new(),
// }
// }
// async fn run(&mut self, _: Vec<String>) -> 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, T: Fn() -> R>(command: T) -> Result<R, Error> { // this command runs when a shell command is executed
// // Ok(command())
// // }
// async fn run_cmd(&mut self, cmd: String, args: Vec<String>) -> 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>), String> {
// let mut args: Vec<String> = Vec::new();
// for arg in command.split(" ").collect::<Vec<&str>>() {
// 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))
// }
// }
+3 -3
View File
@@ -49,11 +49,11 @@ pub struct CrystalFetch {}
#[async_trait]
impl Application for CrystalFetch {
fn new() -> Self {
Self {}
fn new(window: Option<Window>) -> Result<Self, Error> {
Ok(Self {})
}
async fn run(&mut self, window: Option<Window>, _args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
// let ds = Display::borrow();
+3 -3
View File
@@ -15,11 +15,11 @@ pub struct GigachadDetector {}
#[async_trait]
impl Application for GigachadDetector {
fn new() -> Self {
Self {}
fn new(window: Option<Window>) -> Result<Self, Error> {
Ok(Self {})
}
async fn run(&mut self, window: Option<Window>, args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
for arg in args {
self.detect_gigachad_by_username(&arg)
}
+3 -3
View File
@@ -52,11 +52,11 @@ pub struct Rickroll {}
#[async_trait]
impl Application for Rickroll {
fn new() -> Self {
Self {}
fn new(window: Option<Window>) -> Result<Self, Error> {
Ok(Self {})
}
async fn run(&mut self, window: Option<Window>, _args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
println!("{}", RICKROLL2);
Ok(())
}