Compare commits

..

6 Commits

24 changed files with 618 additions and 407 deletions
-24
View File
@@ -1,24 +0,0 @@
name: Rust
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Build Docker Image
run: docker build -t crystal-os .
- name: Run Build in Docker Container
run: docker run --rm crystal-os
+1 -1
View File
@@ -1,4 +1,4 @@
# CrystalOS # ZXQ5.OS
the initial aim of this project was to follow a blog series on how to write an operating system in Rust (see links below) the initial aim of this project was to follow a blog series on how to write an operating system in Rust (see links below)
+15 -2
View File
@@ -4,10 +4,15 @@
#![test_runner(CrystalOS::test_runner)] #![test_runner(CrystalOS::test_runner)]
#![reexport_test_harness_main = "test_main"] #![reexport_test_harness_main = "test_main"]
use alloc::vec::Vec;
use bootloader::{entry_point, BootInfo}; use bootloader::{entry_point, BootInfo};
use core::panic::PanicInfo; use core::panic::PanicInfo;
use CrystalOS::std::tasks::{Executor, Task}; use CrystalOS::std::tasks::{Executor, Task};
use CrystalOS::{printerr, std::syscall}; 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; extern crate alloc;
use CrystalOS::user::bin::shell; use CrystalOS::user::bin::shell;
@@ -16,6 +21,7 @@ use CrystalOS::user::bin::shell;
fn panic(_info: &PanicInfo) -> ! { fn panic(_info: &PanicInfo) -> ! {
syscall::terminal_mode_force(); syscall::terminal_mode_force();
printerr!("{}", _info); printerr!("{}", _info);
serial_println!("{}", _info);
CrystalOS::hlt(); CrystalOS::hlt();
} }
@@ -36,9 +42,16 @@ fn main(boot_info: &'static BootInfo) -> ! {
// runs the 'mainloop' of the OS; // runs the 'mainloop' of the OS;
let mut executor = Executor::new(); 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 { loop {
executor.try_run(); 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();
}
+22 -11
View File
@@ -1,3 +1,4 @@
use alloc::string::String;
use core::fmt; use core::fmt;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use spin::Mutex; use spin::Mutex;
@@ -5,6 +6,7 @@ use volatile::Volatile;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
use crate::serial_println;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -52,6 +54,7 @@ pub enum RenderError {
InvalidCharacter, InvalidCharacter,
InvalidColour, InvalidColour,
InvalidRenderMode, InvalidRenderMode,
Other(&'static str),
} }
impl ScreenChar { impl ScreenChar {
@@ -61,6 +64,14 @@ impl ScreenChar {
colour: ColorCode::new(Color::White, Color::Black), 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 { pub fn white(mut character: u8) -> ScreenChar {
if let Some(c) = special_char(character as char) { if let Some(c) = special_char(character as char) {
character = c; character = c;
@@ -111,19 +122,18 @@ lazy_static! {
impl Renderer { impl Renderer {
// EXTERNAL API : for use by standard library and other parts of the kernel // EXTERNAL API : for use by standard library and other parts of the kernel
pub fn render_frame(&mut self, frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer pub fn render_frame(&mut self, mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer
let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
for (i, row) in frame.iter().enumerate() { for (i, row) in frame.iter_mut().enumerate() {
for (j, col) in row.iter().enumerate() { for (j, col) in row.iter_mut().enumerate() {
processed_frame[i][j] = match special_char(col.character as char) { if col.character == 0u8 { continue; }
Some(c) => ScreenChar::new(c as u8, col.colour), if let Some(c) = special_char(col.character as char) {
None => *col, col.character = c as u8;
}; }
self.app_buffer[i][j] = *col;
} }
} }
self.app_buffer = processed_frame;
self.internal_render(); self.internal_render();
} }
@@ -296,6 +306,7 @@ impl Renderer {
if self.application_mode { if self.application_mode {
for (i, row) in self.app_buffer.iter().enumerate() { for (i, row) in self.app_buffer.iter().enumerate() {
for (j, col) in row.iter().enumerate() { for (j, col) in row.iter().enumerate() {
if col.character == 0u8 { continue; }
self.screen_ref.chars[i][j].write(*col); self.screen_ref.chars[i][j].write(*col);
} }
} }
@@ -362,4 +373,4 @@ pub fn write(args: fmt::Arguments, cols: (Color, Color)) {
writer.write_fmt(args).unwrap(); writer.write_fmt(args).unwrap();
writer.reset_colour(); writer.reset_colour();
}) })
} }
+5 -2
View File
@@ -206,7 +206,10 @@ impl KeyboardHandler {
pub(crate) fn add_scancode(scancode: u8) { pub(crate) fn add_scancode(scancode: u8) {
if let Ok(queue) = SCANCODE_QUEUE.try_get() { if let Ok(queue) = SCANCODE_QUEUE.try_get() {
if let Err(_) = queue.push(scancode) { if let Err(_) = queue.push(scancode) {
println!("WARNING: queue is full - ignoring input"); let _ = queue.pop();
if let Err(_) = queue.push(scancode) {
println!("WARNING: scancode queue is full");
}
} else { } else {
WAKER.wake(); WAKER.wake();
} }
@@ -221,7 +224,7 @@ pub struct ScanCodeStream {
impl ScanCodeStream { impl ScanCodeStream {
pub fn new() -> Self { pub fn new() -> Self {
SCANCODE_QUEUE.try_init_once(|| ArrayQueue::new(100)) SCANCODE_QUEUE.try_init_once(|| ArrayQueue::new(3))
.expect("ScanCodeStream::new has already been called once"); .expect("ScanCodeStream::new has already been called once");
ScanCodeStream { _private: () } ScanCodeStream { _private: () }
} }
+3 -2
View File
@@ -5,9 +5,9 @@ use super::render::Window;
#[async_trait] #[async_trait]
pub trait Application { 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(()) Ok(())
} }
} }
@@ -18,6 +18,7 @@ pub enum Error {
CommandFailed(String), CommandFailed(String),
ApplicationError(String), ApplicationError(String),
EmptyCommand, EmptyCommand,
NoWindow,
} }
pub enum Exit { pub enum Exit {
+183 -33
View File
@@ -4,7 +4,7 @@ use alloc::vec::Vec;
use crate::system::kernel::render::{RENDERER, ScreenChar}; use crate::system::kernel::render::{RENDERER, ScreenChar};
use crate::std::io::Color; use crate::std::io::Color;
use num_traits::{Num, ToPrimitive}; use num_traits::{Num, ToPrimitive};
use crate::serial_println;
/// TODO: get a working implementation for CLI apps /// TODO: get a working implementation for CLI apps
/// elements can be created using their from_str() method /// elements can be created using their from_str() method
/// you can then render the element to the current frame using the render() method /// you can then render the element to the current frame using the render() method
@@ -22,51 +22,183 @@ pub use crate::system::kernel::render::{
}; };
pub struct Window { pub struct Window {
width: u32, width: usize,
height: u32, height: usize,
x: u32, x: usize,
y: u32, y: usize,
bordered: bool, bordered: bool,
open: bool, open: bool,
title: String,
} }
impl Window { impl Window {
pub fn new() -> Window { pub fn new() -> Window {
Window { Window {
width: BUFFER_WIDTH as u32, width: BUFFER_WIDTH,
height: BUFFER_HEIGHT as u32, height: BUFFER_HEIGHT,
x: 0, x: 0,
y: 0, y: 0,
bordered: true, bordered: true,
open: true open: false,
title: String::new(),
} }
} }
pub fn open(&mut self) -> Result<(), RenderError> { pub fn open(&mut self) -> Result<(), RenderError> {
if self.open { RENDERER.lock().application_mode();
return Err(RenderError::InvalidRenderMode);
} if self.open { return Err(RenderError::InvalidRenderMode); }
self.open = true; self.open = true;
self.render(&Frame::from_window(self))?;
let mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
Ok(()) Ok(())
} }
// pub fn render(&self, f: &Frame) -> Result<(), RenderError> { pub fn is_open(&self) -> bool {
// let mut frame: &[[ScreenChar; self.width]; self.height] = &[[ScreenChar::null(); self.width]; self.height]; self.open
}
pub fn dimensions(&self) -> Dimensions<usize> {
Dimensions::new(self.width, self.height)
}
pub fn set_dimensions(&mut self, width: usize, height: usize) {
self.width = width;
self.height = height;
}
pub fn position(&self) -> Position<usize> {
Position::new(self.x, self.y)
}
pub fn set_position(&mut self, x: usize, y: usize) {
self.x = x;
self.y = y;
}
pub fn set_title(&mut self, title: &str) {
self.title = String::from(title);
}
pub fn render(&self, f: &Frame) -> Result<(), RenderError> {
let mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
for (i, row) in f.frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
frame[i + f.position.y][j + f.position.x] = col.as_screen_char();
};
}
if self.bordered {
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]) {
// draws the sides of the container
// Calculate the dimensions
let dimensions = self.dimensions();
// Extract coordinates for readability
let top_y = self.y as isize - 1;
let bottom_y = self.y as isize + dimensions.y as isize;
let left_x = self.x as isize - 1;
let right_x = self.x as isize + dimensions.x as isize;
let x_start = self.x as isize;
let x_end = self.x as isize + dimensions.x as isize;
let y_start = self.y as isize;
let y_end = self.y as isize + dimensions.y as isize;
// Define ranges
let (top, bottom, left, right) = (
(top_y, x_start..x_end),
(bottom_y, x_start..x_end),
(left_x, y_start..y_end),
(right_x, y_start..y_end),
);
let title = self.title.clone();
let title_width = title.len();
let mut title_x = left_x + (dimensions.x as isize - title_width as isize) / 2;
if title_x < left_x {
title_x = left_x;
}
for (y, range) in [top, bottom] {
for x in range {
// for (i, row) in f.frame.iter().enumerate() { if x >= 0 && x < 80 && y >= 0 && y < 25 {
// for (j, col) in row.iter().enumerate() { frame[y as usize][x as usize] = ColouredChar::new('─').as_screen_char();
// frame[i + f.position.y][j + f.position.x] = col.as_screen_char(); }
// }; }
// } }
// RENDERER.lock().render_frame(frame);
// Ok(()) for (x, range) in [left, right] {
// } for y in range {
if x >= 0 && x < 80 && y >= 0 && y < 25 {
frame[y as usize][x as usize] = ColouredChar::new('│').as_screen_char();
}
}
}
for (i, c) in title.chars().enumerate() {
let i = i as isize;
if title_x + i >= 0 && title_x + i < 80 && top_y >= 0 && top_y < 25 {
frame[top_y as usize][(title_x + i as isize) as usize] = ColouredChar::new(c).as_screen_char();
}
}
// draw the corners of the container
let corners = [
(top_y, left_x, '┌'),
(top_y, right_x, '┐'),
(bottom_y, left_x, '└'),
(bottom_y, right_x, '┘'),
];
for &(y, x, c) in &corners {
if x >= 0 && x < 80 && y >= 0 && y < 25 {
frame[y as usize][x as usize] = ColouredChar::new(c).as_screen_char();
}
}
}
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) {
if self.open {
self.close()
}
}
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
@@ -85,7 +217,14 @@ impl ColouredChar {
colour: ColorCode::new(Color::White, Color::Black), 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 { ColouredChar {
character: ' ', character: ' ',
colour: ColorCode::new(Color::White, Color::Black), colour: ColorCode::new(Color::White, Color::Black),
@@ -103,11 +242,9 @@ impl ColouredChar {
colour: self.colour, colour: self.colour,
} }
} }
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct Position<T: Num> { pub struct Position<T: Num> {
pub x: T, pub x: T,
@@ -160,7 +297,7 @@ impl Frame {
Ok(Frame { Ok(Frame {
position, position,
dimensions, dimensions,
frame: vec![vec![ColouredChar::null(); dimensions.x]; dimensions.y], frame: vec![vec![ColouredChar::blank(); dimensions.x]; dimensions.y],
}) })
} }
@@ -168,7 +305,7 @@ impl Frame {
Frame { Frame {
dimensions: Dimensions::new(window.width as usize, window.height as usize), dimensions: Dimensions::new(window.width as usize, window.height as usize),
position: Position::new(window.x as usize, window.y 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],
} }
} }
@@ -267,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 { impl core::ops::Index<usize> for Frame {
type Output = Vec<ColouredChar>; type Output = Vec<ColouredChar>;
fn index(&self, index: usize) -> &Self::Output { fn index(&self, index: usize) -> &Self::Output {
+6 -7
View File
@@ -3,9 +3,10 @@ use alloc::{boxed::Box, format, string::String, vec::Vec};
use alloc::string::ToString; use alloc::string::ToString;
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use crate::std::render::Window; use crate::std::render::Window;
use crate::{println, print, mknode, std, serial_println}; use crate::{println, print, mknode, std};
use async_trait::async_trait; use async_trait::async_trait;
use crate::std::application;
use crate::std::application::{ use crate::std::application::{
Application, Application,
Error as ShellError Error as ShellError
@@ -358,11 +359,11 @@ pub struct Calculator {}
#[async_trait] #[async_trait]
impl Application for Calculator { impl Application for Calculator {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Calculator, application::Error> {
Self {} 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 { if args.len() == 0 {
loop { loop {
print!("enter equation > "); print!("enter equation > ");
@@ -420,9 +421,7 @@ impl Calculator {
"failed to tokenise: {:?}", "failed to tokenise: {:?}",
e e
))?; ))?;
serial_println!("{:?}", tokens);
let mut parser = Parser::new(tokens).unwrap(); let mut parser = Parser::new(tokens).unwrap();
parser.parse().map_err(|e| format!("{:?}", e)) parser.parse().map_err(|e| format!("{:?}", e))
} }
+46 -63
View File
@@ -20,8 +20,8 @@ pub struct Editor {
command: String, command: String,
mode: Mode, mode: Mode,
unsaved: bool, unsaved: bool,
display: Display,
lineno_width: i32, lineno_width: i32,
window: Window,
} }
enum Mode { enum Mode {
@@ -36,7 +36,7 @@ impl core::fmt::Display for Mode {
match self { match self {
Mode::Normal => write!(f, "Normal"), Mode::Normal => write!(f, "Normal"),
Mode::Insert => write!(f, "Insert"), Mode::Insert => write!(f, "Insert"),
Mode::Command => write!(f, "Commnd"), Mode::Command => write!(f, "Cmmd "),
Mode::Diff => write!(f, "Diff "), Mode::Diff => write!(f, "Diff "),
} }
} }
@@ -67,38 +67,25 @@ impl Editor {
self.cursor_pos.x += dx; self.cursor_pos.x += dx;
} }
serial_println!("cursor: {} {} offset: {} {} ", self.cursor_pos.x, self.cursor_pos.y, self.offset_pos.x, self.offset_pos.y); while self.cursor_pos.x + 2 + (self.lineno_width + 2) > self.window.dimensions().x as i32 + self.offset_pos.x {
while self.cursor_pos.x + 3 + (self.lineno_width + 2) > 80 + self.offset_pos.x {
self.offset_pos.x += 1; self.offset_pos.x += 1;
} }
while self.cursor_pos.x - 3 < self.offset_pos.x && self.offset_pos.x - 3 >= 0 { while self.cursor_pos.x - 3 < self.offset_pos.x && self.offset_pos.x - 1 >= 0 {
self.offset_pos.x -= 1; self.offset_pos.x -= 1;
} }
while self.cursor_pos.y + 3 > self.offset_pos.y + 25 { while self.cursor_pos.y + 3 > self.offset_pos.y + self.window.dimensions().y as i32 {
self.offset_pos.y += 1; self.offset_pos.y += 1;
} }
while self.cursor_pos.y - 3 < self.offset_pos.y && self.offset_pos.y - 3 >= 0 { while self.cursor_pos.y - 1 < self.offset_pos.y && self.offset_pos.y - 1 >= 0 {
self.offset_pos.y -= 1; self.offset_pos.y -= 1;
} }
serial_println!( self.window.move_cursor(
"moving cursor to {}, {}", self.cursor_pos.x - self.offset_pos.x + self.lineno_width + 2,
(self.cursor_pos.x - self.offset_pos.x + self.lineno_width + 2) as u8, self.cursor_pos.y - self.offset_pos.y
(self.cursor_pos.y - self.offset_pos.y) as u8
);
// print all the values below
serial_println!("offset: {}, {}", self.offset_pos.x, self.offset_pos.y);
serial_println!("cursor: {}, {}", self.cursor_pos.x, self.cursor_pos.y);
serial_println!("line width: {}", self.lineno_width + 2);
self.display.mv_cursor(
(self.cursor_pos.x - self.offset_pos.x + self.lineno_width + 2) as u8,
(self.cursor_pos.y - self.offset_pos.y) as u8
).unwrap(); ).unwrap();
} }
@@ -156,43 +143,39 @@ impl ToString for Editor {
#[async_trait] #[async_trait]
impl Application for Editor { impl Application for Editor {
fn new() -> Editor { fn new(window: Option<Window>) -> Result<Editor, application::Error> {
Editor { let window = if let Some(window) = window { window } else { return Err(application::Error::NoWindow) };
Ok(Editor {
buffer: Vec::new(), buffer: Vec::new(),
cursor_pos: Position::zero(), cursor_pos: Position::zero(),
offset_pos: Position::zero(), offset_pos: Position::zero(),
command: String::new(), command: String::new(),
mode: Mode::Normal, mode: Mode::Normal,
unsaved: false, unsaved: false,
display: Display::borrow(), lineno_width: 0,
lineno_width: 0 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(s) = args.get(0) { self.window.set_dimensions(60, 15);
// self.buffer = s.lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>() self.window.set_position(10, 3);
// } self.window.set_title("Editor");
self.window.open();
self.buffer = String::from(" if let Some(s) = args.get(0) {
/$$ /$$$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$$ /$$ /$$ /$$ self.buffer = s.lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>()
/$$/|_____ $$ | $$ / $$ /$$__ $$| $$____/ /$$/| $$| $$ }
/$$/ /$$/ | $$/ $$/| $$ \\ $$| $$ /$$/ \\ $$\\ $$
/$$/ /$$/ \\ $$$$/ | $$ | $$| $$$$$$$ /$$/ \\ $$\\ $$
| $$ /$$/ >$$ $$ | $$ | $$|_____ $$ /$$/ /$$/ /$$/
\\ $$ /$$/ /$$/\\ $$| $$/$$ $$ /$$ \\ $$ /$$/ /$$/ /$$/
\\ $$ /$$$$$$$$| $$ \\ $$| $$$$$$/| $$$$$$//$$/ /$$/ /$$/
\\__/|________/|__/ |__/ \\____ $$$ \\______/|__/ |__/ |__/
\\__/
").lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>();
loop { loop {
// start by rendering the screen // start by rendering the screen
self.lineno_width = self.buffer.len().to_string().len() as i32; self.lineno_width = self.buffer.len().to_string().len() as i32;
self.render().unwrap().write_to_screen().unwrap();
if let Ok(frame) = self.render() {
self.window.render(&frame).unwrap();
}
// wait for a keyboard input // wait for a keyboard input
let keystroke = std::io::Stdin::keystroke().await; let keystroke = std::io::Stdin::keystroke().await;
@@ -203,19 +186,12 @@ impl Application for Editor {
KeyStroke::Char('i') => self.mode = Mode::Insert, KeyStroke::Char('i') => self.mode = Mode::Insert,
KeyStroke::Char(':') => self.mode = Mode::Command, KeyStroke::Char(':') => self.mode = Mode::Command,
KeyStroke::Char('d') => self.mode = Mode::Diff, KeyStroke::Char('d') => self.mode = Mode::Diff,
KeyStroke::Char('`') => { KeyStroke::Char('`') => return Ok(()),
// TODO: End terminal session
// ncurses::endwin();
return Ok(());
}
_ => {} _ => {}
} }
}, },
Mode::Insert => { Mode::Insert => {
match keystroke { match keystroke {
KeyStroke::Enter => {
// TODO: newline function
},
KeyStroke::Char(c) => { KeyStroke::Char(c) => {
match c { match c {
// escape // escape
@@ -247,12 +223,8 @@ impl Application for Editor {
KeyStroke::Down => { KeyStroke::Down => {
self.move_cursor(0, 1); self.move_cursor(0, 1);
}, },
KeyStroke::None => { KeyStroke::None => {},
serial_println!("none"); _ => {}
},
_ => {
serial_println!("other");
}
} }
} }
Mode::Command => { Mode::Command => {
@@ -280,11 +252,11 @@ impl Application for Editor {
impl CgComponent for Editor { impl CgComponent for Editor {
fn render(&self) -> Result<Frame, RenderError> { fn render(&self) -> Result<Frame, RenderError> {
let mut frame = Frame::new(Position::zero(), Position::new(80, 25))?; let mut frame = Frame::new(self.window.position(), self.window.dimensions())?;
let width = self.lineno_width as usize; let width = self.lineno_width as usize;
let linecolour = ColorCode::new(Color::Cyan, Color::Black); let linecolour = ColorCode::new(Color::Cyan, Color::Black);
for (i, line) in (self.offset_pos.y..self.offset_pos.y + 24).enumerate() { for (i, line) in (self.offset_pos.y..self.offset_pos.y + self.window.dimensions().y as i32 - 1).enumerate() {
if line >= self.buffer.len() as i32 { if line >= self.buffer.len() as i32 {
break; break;
} }
@@ -297,7 +269,7 @@ impl CgComponent for Editor {
let line = self.buffer[line as usize].iter().collect::<String>(); let line = self.buffer[line as usize].iter().collect::<String>();
for (j, c) in line.chars().skip(self.offset_pos.x as usize).take(80 - (width + 2)).enumerate() { for (j, c) in line.chars().skip(self.offset_pos.x as usize).take(self.window.dimensions().x - (width + 2)).enumerate() {
frame.write(Position::new(j + width + 2, i), ColouredChar::new(c))?; frame.write(Position::new(j + width + 2, i), ColouredChar::new(c))?;
} }
} }
@@ -317,7 +289,7 @@ impl CgComponent for Editor {
let toolbar = line_and_col + " " + &mode + " " + &unsaved; let toolbar = line_and_col + " " + &mode + " " + &unsaved;
for (i, c) in toolbar.chars().enumerate() { for (i, c) in toolbar.chars().enumerate() {
frame.write(Position::new(i, 24), ColouredChar::new(c))?; frame.write(Position::new(i, self.window.dimensions().y - 1), ColouredChar::new(c))?;
} }
Ok(frame) Ok(frame)
@@ -328,3 +300,14 @@ impl CgComponent for Editor {
} }
} }
// self.buffer = String::from("
// /$$ /$$$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$$ /$$ /$$ /$$
// /$$/|_____ $$ | $$ / $$ /$$__ $$| $$____/ /$$/| $$| $$
// /$$/ /$$/ | $$/ $$/| $$ \\ $$| $$ /$$/ \\ $$\\ $$
// /$$/ /$$/ \\ $$$$/ | $$ | $$| $$$$$$$ /$$/ \\ $$\\ $$
// | $$ /$$/ >$$ $$ | $$ | $$|_____ $$ /$$/ /$$/ /$$/
// \\ $$ /$$/ /$$/\\ $$| $$/$$ $$ /$$ \\ $$ /$$/ /$$/ /$$/
// \\ $$ /$$$$$$$$| $$ \\ $$| $$$$$$/| $$$$$$//$$/ /$$/ /$$/
// \\__/|________/|__/ |__/ \\____ $$$ \\______/|__/ |__/ |__/
// \\__/
// ").lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>();
+7 -12
View File
@@ -43,13 +43,14 @@ struct PointI64 {
#[async_trait] #[async_trait]
impl Application for Grapher { impl Application for Grapher {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Self { Ok(Self {
points: Vec::new(), points: Vec::new(),
frame: Frame::new(Position::new(1, 1), Dimensions::new(78, 22)).unwrap() 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(); let _d = Display::borrow();
self.frame.frame = vec![vec![ColouredChar::new(' '); self.frame.dimensions.x]; self.frame.dimensions.y]; 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(()); return Ok(());
} }
else { else {
let mut container = CgContainer::new( let mut container = CgContainer::new(
Position::new(0, 0), Position::new(0, 0),
@@ -136,13 +138,6 @@ impl Application for Grapher {
entry_widget.update(entry); entry_widget.update(entry);
if let Ok(frame) = container.render() { if let Ok(frame) = container.render() {
let self_widget = container.elements.get("grapher").unwrap();
let _self_clone = self_widget.fetch::<Grapher>().unwrap();
let entry = container.elements.get("entry_box").unwrap();
let _entry_clone = entry.fetch::<CgLineEdit>().unwrap();
frame.write_to_screen().map_err(|_| Error::ApplicationError(String::from("failed to write to screen")))?; frame.write_to_screen().map_err(|_| Error::ApplicationError(String::from("failed to write to screen")))?;
} }
} }
@@ -156,7 +151,7 @@ impl Grapher {
fn graph_equation(&mut self, equation: String, offsets: (i64, i64)) { 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| { let ast = cal.get_expr(equation.chars().map(|c| {
match c { match c {
'e' => format!("({})", E), 'e' => format!("({})", E),
+4 -2
View File
@@ -26,9 +26,11 @@ pub struct Tasks;
#[async_trait] #[async_trait]
impl Application for Tasks { 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") { if args[0].clone() == String::from("add") {
+227 -14
View File
@@ -1,27 +1,68 @@
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}; use crate::std::{application::{Application, Error}, render::Window};
use async_trait::async_trait; use async_trait::async_trait;
use vga::writers::PrimitiveDrawing;
use crate::apps::calc::Calculator;
use crate::apps::editor::Editor;
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, 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;
use crate::utils::gigachad_detector::GigachadDetector;
use crate::utils::rickroll::Rickroll;
pub struct ZxqSH { pub struct ZxqSH {
history: Vec<String>, history: Vec<String>,
idx: u32, history_idx: usize,
window: Window, window: Window,
// 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] #[async_trait]
impl Application for ZxqSH { impl Application for ZxqSH {
fn new() -> Self { fn new(window: Option<Window>) -> Result<ZxqSH, Error> {
todo!() 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 { loop {
if let Ok(exit) = self.next().await { match self.next().await {
if exit { return Ok(()) } Err(e) => {
self.write(format!("Error: {:?}", e), Color::Yellow);
return Err(e);
},
Ok(exit) => {
if exit { return Ok(()) }
}
} }
} }
} }
@@ -32,19 +73,191 @@ impl ZxqSH {
// update cycle for the shell // update cycle for the shell
// TOOD: prompt // TODO: prompt
let mut command = self.input().await;
// TODO: exit if necessar // TODO: exit if necessary
// TODO: execute command // TODO: execute command
if let Err(e) = self.execute(command, Vec::new()).await {
// return match e {
Error::UnknownCommand(e) => {
self.write("Unknown command\n".to_string(), Color::Yellow);
}
_ => {
self.write(format!("Error: {:?}\n", e), Color::Yellow);
}
}
}
Ok(false) Ok(false)
} }
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> {
let window = Window::new();
match cmd.as_str() {
"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};
let mode = Graphics640x480x16::new();
mode.set_mode();
mode.clear_screen(Color16::Black);
mode.draw_line((80, 60), (120, 420), Color16::Cyan);
},
"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(Some(window)).expect("couldn't open window").run(Vec::new()).await?,
"games/tetris" => {
// games::tetris::TetrisEngine::new().expect("couldn't open window").run(Vec::new()).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!(
"Crystal: '{}'",
args.into_iter()
.map(|mut s| {
s.push_str(" ");
s
})
.collect::<String>()
)
}
"clear" => Display::clear(),
"time" => timer(),
_ => return Err(Error::UnknownCommand(cmd))
};
if let Ok(frame) = self.render() {
self.window.render(&frame).unwrap();
}
async fn execute(&self, command: String) -> Result<(), Error> {
Ok(()) Ok(())
} }
}
impl CgComponent for ZxqSH {
fn render(&self) -> Result<Frame, RenderError> {
let mut frame = Frame::from_window(&self.window);
let term_height = self.window.dimensions().y;
let term_width = self.window.dimensions().x;
self.window.move_cursor(self.get_col() as i32, term_height as i32 - 1)?;
// render the contents of the terminal to a frame
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)
}
fn as_any(&self) -> &dyn Any {
self as &dyn Any
}
} }
+4 -4
View File
@@ -41,8 +41,8 @@ pub struct Game {
#[async_trait] #[async_trait]
impl Application for Game { impl Application for Game {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Self { Ok(Self {
player: Player::new(), player: Player::new(),
enemies: Vec::new(), enemies: Vec::new(),
score: 0, score: 0,
@@ -50,9 +50,9 @@ impl Application for Game {
difficulty_idx: 1, difficulty_idx: 1,
gamespeed: 1.0, gamespeed: 1.0,
timer: GameTimer::new(), 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 _d = Display::borrow();
let mut container_data = let mut container_data =
+4 -5
View File
@@ -21,19 +21,18 @@ pub enum Cell {
#[async_trait] #[async_trait]
impl Application for Game { impl Application for Game {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Game { Ok(Game {
board: [[Cell::Empty; 7]; 6], board: [[Cell::Empty; 7]; 6],
turn: 1, turn: 1,
vs_ai: false, vs_ai: false,
game_over: false, game_over: false,
winner: None, 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(); let _display = Display::borrow();
self.get_next_mode().await; self.get_next_mode().await;
// Main game loop // Main game loop
+14 -7
View File
@@ -1,9 +1,10 @@
use alloc::string::String; use alloc::string::String;
use alloc::vec; use alloc::{format, vec};
use alloc::vec::Vec; use alloc::vec::Vec;
use alloc::boxed::Box; use alloc::boxed::Box;
use crate::std::application::{Application, Error}; use crate::std::application::{Application, Error};
use async_trait::async_trait; use async_trait::async_trait;
use futures_util::future::err;
use crate::std::render::{ColouredChar, Dimensions, Frame, Position, RenderError, Window}; use crate::std::render::{ColouredChar, Dimensions, Frame, Position, RenderError, Window};
use crate::std::io::{KeyStroke, Stdin, Color, ColorCode, Display}; use crate::std::io::{KeyStroke, Stdin, Color, ColorCode, Display};
use crate::std::time::wait; use crate::std::time::wait;
@@ -16,12 +17,18 @@ const LOOP_SPEED: f64 = 0.1;
#[async_trait] #[async_trait]
impl Application for GameOfLife { impl Application for GameOfLife {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Self { let mut frame: Frame;
frame: Frame::new(Position::new(0, 0), Dimensions::new(80, 25)).unwrap() 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: // setup:
let _d = Display::borrow(); 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)) { 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)); return ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black));
} else { } else {
return ColouredChar::null(); return ColouredChar::blank();
} }
} else if alive == 3 { } else if alive == 3 {
ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black)) ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black))
} else { } else {
ColouredChar::null() ColouredChar::blank()
} }
} }
+4 -4
View File
@@ -33,8 +33,8 @@ pub struct GameBoard {
#[async_trait] #[async_trait]
impl Application for GameBoard { impl Application for GameBoard {
fn new() -> GameBoard { fn new(window: Option<Window>) -> Result<Self, Error> {
GameBoard { Ok(GameBoard {
board: [[Cell::Empty; 80]; 25], board: [[Cell::Empty; 80]; 25],
players: [ players: [
Player::new(0, (10, 10), false), Player::new(0, (10, 10), false),
@@ -46,10 +46,10 @@ impl Application for GameBoard {
], ],
max_territory: 0, max_territory: 0,
current_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(); let _display = Display::borrow();
'outer: loop { 'outer: loop {
+4 -4
View File
@@ -17,15 +17,15 @@ pub(crate) struct Game {
#[async_trait] #[async_trait]
impl Application for Game { impl Application for Game {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Game { Ok(Game {
ball: Ball::new(), ball: Ball::new(),
player1: Player::new(1), player1: Player::new(1),
player2: Player::new(78), 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 _d = Display::borrow();
let mut update_time = Timer::new(0.1); 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 alloc::{format, vec, vec::Vec, boxed::Box};
use async_trait::async_trait; use async_trait::async_trait;
use crate::std::io::{Color, Display, KeyStroke, Stdin}; use crate::std::io::{Color, Display, KeyStroke, Stdin};
@@ -30,22 +30,34 @@ pub struct Game {
pois: Vec<Position>, pois: Vec<Position>,
score: u8, score: u8,
gamemode: Gamemode, gamemode: Gamemode,
window: Window,
} }
#[async_trait] #[async_trait]
impl Application for Game { impl Application for Game {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Self { let window = match window {
Some(w) => w,
None => return Err(Error::NoWindow),
};
Ok(Self {
snakes: Vec::new(), snakes: Vec::new(),
pois: Vec::new(), pois: Vec::new(),
score: 0, 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 let _settings = [0, 0, 0]; // ai_count, snake_len, poi_count
@@ -75,7 +87,6 @@ impl Application for Game {
self.prepare(); self.prepare();
// switch OS to application mode // switch OS to application mode
let _d = Display::borrow();
// render the initial state of the screen. // render the initial state of the screen.
self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?; self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
// run the game // run the game
@@ -154,7 +165,7 @@ impl Game {
} }
fn new_poi(&mut self) { 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) { fn replace_poi(&mut self, poi: &Position) {
@@ -164,7 +175,7 @@ impl Game {
fn render(&mut self) -> Result<(), RenderError> { 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); let mut curr_colour = ColorCode::new(Color::LightBlue, Color::Black);
for s in self.snakes.clone() { for s in self.snakes.clone() {
@@ -182,15 +193,14 @@ impl Game {
}); });
let literal = format!("snake go brr score: {}", self.score); 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)| { msg.chars().enumerate().for_each(|(i, c)| {
if c != ' ' { if c != ' ' {
frame[1][i] = ColouredChar::coloured(c, ColorCode::new(Color::LightGreen, Color::Black)) frame[1][i] = ColouredChar::coloured(c, ColorCode::new(Color::LightGreen, Color::Black))
} }
}); });
frame.write_to_screen()?; self.window.render(&frame)?;
Ok(()) 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[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[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(()) Ok(())
} }
} }
-1
View File
@@ -2,4 +2,3 @@ pub mod apps;
pub mod games; pub mod games;
pub mod utils; pub mod utils;
pub mod shell; pub mod shell;
pub mod shellrewrite;
+36 -28
View File
@@ -48,6 +48,7 @@ use crate::{
} }
}, },
}; };
use crate::apps::zxqsh::ZxqSH;
lazy_static! { lazy_static! {
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new()); pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
@@ -66,11 +67,11 @@ pub async fn eventloop() {
let window = Window::new(); let window = Window::new();
let mut fetch = CrystalFetch::new(); let mut fetch = CrystalFetch::new(Some(window)).unwrap();
let string = String::from(" "); let string = String::from(" ");
let mut vec: Vec<String> = Vec::new(); let mut vec: Vec<String> = Vec::new();
vec.push(string); vec.push(string);
fetch.run(Some(window), vec).await.unwrap(); fetch.run(vec).await.unwrap();
CMD.lock().prompt(); CMD.lock().prompt();
@@ -103,6 +104,9 @@ fn handle_error(e: Error) {
Error::CommandFailed(e) => { Error::CommandFailed(e) => {
printerr!("command failed:\n{}", e); printerr!("command failed:\n{}", e);
}, },
Error::NoWindow => {
printerr!("no window");
}
} }
} }
@@ -125,27 +129,27 @@ async fn exec() -> Result<(), Error> {
match cmd.as_str() { match cmd.as_str() {
"calculate" | "calc" | "solve" => { "calculate" | "calc" | "solve" => {
let mut cmd = Calculator::new(); let mut cmd = Calculator::new(Some(window)).expect("couldn't open window");
cmd.run(Some(window), args).await?; cmd.run(args).await?;
} }
"games/connect4" => { "games/connect4" => {
let mut cmd = Connect4Game::new(); let mut cmd = Connect4Game::new(Some(window)).expect("couldn't open window");
cmd.run(Some(window), args).await?; cmd.run(args).await?;
} }
"rickroll" => { "rickroll" => {
let mut cmd = Rickroll::new(); let mut cmd = Rickroll::new(Some(window)).expect("couldn't open window");
cmd.run(Some(window), args).await?; cmd.run(args).await?;
} }
"crystalfetch" => { "crystalfetch" => {
let mut cmd = CrystalFetch::new(); let mut cmd = CrystalFetch::new(Some(window)).expect("couldn't open window");
cmd.run(Some(window), args).await?; cmd.run(args).await?;
} }
"tasks" => { "tasks" => {
let mut cmd = Tasks::new(); let mut cmd = Tasks::new(Some(window)).expect("couldn't open window");
cmd.run(Some(window), args).await?; cmd.run(args).await?;
} }
"VGA" => { "VGA" => {
use vga::colors::Color16; use vga::colors::Color16;
@@ -157,45 +161,49 @@ async fn exec() -> Result<(), Error> {
mode.draw_line((80, 60), (120, 420), Color16::Cyan); mode.draw_line((80, 60), (120, 420), Color16::Cyan);
} }
"graph" => { "graph" => {
Grapher::new().run(Some(window), args).await?; Grapher::new(Some(window)).expect("couldn't open window").run(args).await?;
} }
"games/snake" => { "games/snake" => {
SnakeGame::new().run(Some(window), args).await?; SnakeGame::new(Some(window)).expect("couldn't open window").run(args).await?;
} }
"games/asteroids" => { "games/asteroids" => {
let mut asteroid_game = AsteroidsGame::new(); let mut cmd = AsteroidsGame::new(Some(window)).expect("couldn't open window");
asteroid_game.run(Some(window), args).await?; cmd.run(args).await?;
} }
"games/pong" => { "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" => { "games/paper.rs" => {
let mut game = GameBoard::new(); let mut cmd = GameBoard::new(Some(window)).expect("couldn't open window");
game.run(Some(window), args).await?; cmd.run(args).await?;
} }
"serial" => { "serial" => {
let c = Serial::reply_char('e'); let c = Serial::reply_char('e');
println!("{}", c); println!("{}", c);
} }
"games/gameoflife" => { "games/gameoflife" => {
let mut game = GameOfLife::new(); let mut cmd = GameOfLife::new(Some(window)).expect("couldn't open window");
game.run(Some(window), Vec::new()).await?; cmd.run(Vec::new()).await?;
} }
"games/tetris" => { "games/tetris" => {
// let mut game = TetrisEngine::new(); // let mut cmd = TetrisEngine::new(Some(window)).expect("couldn't open window");
// game.run(Vec::new()).await?; // cmd.run(Vec::new()).await?;
},
"shell" => {
let mut cmd = ZxqSH::new(Some(window)).expect("couldn't open window");
cmd.run(args).await?;
} }
"gigachad?" => { "gigachad?" => {
let mut detector = GigachadDetector::new(); let mut cmd = GigachadDetector::new(Some(window)).expect("couldn't open window");
detector.run(Some(window), args).await?; cmd.run(args).await?;
} }
"editor" => { "editor" => {
let mut editor = Editor::new(); let mut cmd = Editor::new(Some(window)).expect("couldn't open window");
editor.run(Some(window), args).await?; cmd.run(args).await?;
} }
// direct OS functions (not applications) // direct OS functions (not applications)
"echo" => { "echo" => {
println!( 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))
// }
// }
+4 -4
View File
@@ -49,13 +49,13 @@ pub struct CrystalFetch {}
#[async_trait] #[async_trait]
impl Application for CrystalFetch { impl Application for CrystalFetch {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Self {} 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(); // let ds = Display::borrow();
let os = OS.lock().os.clone(); let os = OS.lock().os.clone();
let version = OS.lock().version.clone(); let version = OS.lock().version.clone();
+3 -3
View File
@@ -15,11 +15,11 @@ pub struct GigachadDetector {}
#[async_trait] #[async_trait]
impl Application for GigachadDetector { impl Application for GigachadDetector {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Self {} 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 { for arg in args {
self.detect_gigachad_by_username(&arg) self.detect_gigachad_by_username(&arg)
} }
+3 -3
View File
@@ -52,11 +52,11 @@ pub struct Rickroll {}
#[async_trait] #[async_trait]
impl Application for Rickroll { impl Application for Rickroll {
fn new() -> Self { fn new(window: Option<Window>) -> Result<Self, Error> {
Self {} 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); println!("{}", RICKROLL2);
Ok(()) Ok(())
} }