Compare commits
5 Commits
ee0963fafd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b278475cb | |||
| 1e7d513f26 | |||
| 1ace354158 | |||
| 41a6b6740b | |||
| c3c4633cf1 |
@@ -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)
|
||||
|
||||
|
||||
+15
-2
@@ -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, 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;
|
||||
use CrystalOS::user::bin::shell;
|
||||
|
||||
@@ -16,6 +21,7 @@ use CrystalOS::user::bin::shell;
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
syscall::terminal_mode_force();
|
||||
printerr!("{}", _info);
|
||||
serial_println!("{}", _info);
|
||||
CrystalOS::hlt();
|
||||
}
|
||||
|
||||
@@ -36,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();
|
||||
}
|
||||
+21
-10
@@ -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)]
|
||||
@@ -52,6 +54,7 @@ pub enum RenderError {
|
||||
InvalidCharacter,
|
||||
InvalidColour,
|
||||
InvalidRenderMode,
|
||||
Other(&'static str),
|
||||
}
|
||||
|
||||
impl ScreenChar {
|
||||
@@ -61,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;
|
||||
@@ -111,19 +122,18 @@ lazy_static! {
|
||||
|
||||
impl Renderer {
|
||||
// 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
|
||||
let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
|
||||
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().enumerate() {
|
||||
for (j, col) in row.iter().enumerate() {
|
||||
processed_frame[i][j] = match special_char(col.character as char) {
|
||||
Some(c) => ScreenChar::new(c as u8, col.colour),
|
||||
None => *col,
|
||||
};
|
||||
}
|
||||
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 = processed_frame;
|
||||
self.app_buffer[i][j] = *col;
|
||||
}
|
||||
}
|
||||
self.internal_render();
|
||||
}
|
||||
|
||||
@@ -296,6 +306,7 @@ impl Renderer {
|
||||
if self.application_mode {
|
||||
for (i, row) in self.app_buffer.iter().enumerate() {
|
||||
for (j, col) in row.iter().enumerate() {
|
||||
if col.character == 0u8 { continue; }
|
||||
self.screen_ref.chars[i][j].write(*col);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,10 @@ impl KeyboardHandler {
|
||||
pub(crate) fn add_scancode(scancode: u8) {
|
||||
if let Ok(queue) = SCANCODE_QUEUE.try_get() {
|
||||
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 {
|
||||
WAKER.wake();
|
||||
}
|
||||
@@ -221,7 +224,7 @@ pub struct ScanCodeStream {
|
||||
|
||||
impl ScanCodeStream {
|
||||
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");
|
||||
ScanCodeStream { _private: () }
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+181
-31
@@ -4,7 +4,7 @@ use alloc::vec::Vec;
|
||||
use crate::system::kernel::render::{RENDERER, ScreenChar};
|
||||
use crate::std::io::Color;
|
||||
use num_traits::{Num, ToPrimitive};
|
||||
|
||||
use crate::serial_println;
|
||||
/// TODO: get a working implementation for CLI apps
|
||||
/// elements can be created using their from_str() 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 {
|
||||
width: u32,
|
||||
height: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: usize,
|
||||
height: usize,
|
||||
x: usize,
|
||||
y: usize,
|
||||
bordered: bool,
|
||||
open: bool,
|
||||
title: String,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new() -> Window {
|
||||
Window {
|
||||
width: BUFFER_WIDTH as u32,
|
||||
height: BUFFER_HEIGHT as u32,
|
||||
width: BUFFER_WIDTH,
|
||||
height: BUFFER_HEIGHT,
|
||||
x: 0,
|
||||
y: 0,
|
||||
bordered: true,
|
||||
open: true
|
||||
open: false,
|
||||
title: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(&mut self) -> Result<(), RenderError> {
|
||||
if self.open {
|
||||
return Err(RenderError::InvalidRenderMode);
|
||||
}
|
||||
RENDERER.lock().application_mode();
|
||||
|
||||
if self.open { return Err(RenderError::InvalidRenderMode); }
|
||||
|
||||
self.open = true;
|
||||
|
||||
let mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
|
||||
|
||||
|
||||
self.render(&Frame::from_window(self))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// pub fn render(&self, f: &Frame) -> Result<(), RenderError> {
|
||||
// let mut frame: &[[ScreenChar; self.width]; self.height] = &[[ScreenChar::null(); self.width]; self.height];
|
||||
pub fn is_open(&self) -> bool {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
// };
|
||||
// }
|
||||
// RENDERER.lock().render_frame(frame);
|
||||
// Ok(())
|
||||
// }
|
||||
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 {
|
||||
if x >= 0 && x < 80 && y >= 0 && y < 25 {
|
||||
frame[y as usize][x as usize] = ColouredChar::new('─').as_screen_char();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
@@ -85,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),
|
||||
@@ -103,11 +242,9 @@ impl ColouredChar {
|
||||
colour: self.colour,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Position<T: Num> {
|
||||
pub x: T,
|
||||
@@ -160,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],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -168,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],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
type Output = Vec<ColouredChar>;
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
|
||||
@@ -3,9 +3,10 @@ use alloc::{boxed::Box, format, string::String, vec::Vec};
|
||||
use alloc::string::ToString;
|
||||
use alloc::borrow::ToOwned;
|
||||
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 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 > ");
|
||||
@@ -421,8 +422,6 @@ impl Calculator {
|
||||
e
|
||||
))?;
|
||||
|
||||
serial_println!("{:?}", tokens);
|
||||
|
||||
let mut parser = Parser::new(tokens).unwrap();
|
||||
parser.parse().map_err(|e| format!("{:?}", e))
|
||||
}
|
||||
|
||||
+46
-63
@@ -20,8 +20,8 @@ pub struct Editor {
|
||||
command: String,
|
||||
mode: Mode,
|
||||
unsaved: bool,
|
||||
display: Display,
|
||||
lineno_width: i32,
|
||||
window: Window,
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
@@ -36,7 +36,7 @@ impl core::fmt::Display for Mode {
|
||||
match self {
|
||||
Mode::Normal => write!(f, "Normal"),
|
||||
Mode::Insert => write!(f, "Insert"),
|
||||
Mode::Command => write!(f, "Commnd"),
|
||||
Mode::Command => write!(f, "Cmmd "),
|
||||
Mode::Diff => write!(f, "Diff "),
|
||||
}
|
||||
}
|
||||
@@ -67,38 +67,25 @@ impl Editor {
|
||||
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 + 3 + (self.lineno_width + 2) > 80 + self.offset_pos.x {
|
||||
while self.cursor_pos.x + 2 + (self.lineno_width + 2) > self.window.dimensions().x as i32 + self.offset_pos.x {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
serial_println!(
|
||||
"moving cursor to {}, {}",
|
||||
(self.cursor_pos.x - self.offset_pos.x + self.lineno_width + 2) as u8,
|
||||
(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
|
||||
self.window.move_cursor(
|
||||
self.cursor_pos.x - self.offset_pos.x + self.lineno_width + 2,
|
||||
self.cursor_pos.y - self.offset_pos.y
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
@@ -156,43 +143,39 @@ 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(),
|
||||
command: String::new(),
|
||||
mode: Mode::Normal,
|
||||
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> {
|
||||
|
||||
// if let Some(s) = args.get(0) {
|
||||
// self.buffer = s.lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>()
|
||||
// }
|
||||
|
||||
self.buffer = String::from("
|
||||
/$$ /$$$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$$ /$$ /$$ /$$
|
||||
/$$/|_____ $$ | $$ / $$ /$$__ $$| $$____/ /$$/| $$| $$
|
||||
/$$/ /$$/ | $$/ $$/| $$ \\ $$| $$ /$$/ \\ $$\\ $$
|
||||
/$$/ /$$/ \\ $$$$/ | $$ | $$| $$$$$$$ /$$/ \\ $$\\ $$
|
||||
| $$ /$$/ >$$ $$ | $$ | $$|_____ $$ /$$/ /$$/ /$$/
|
||||
\\ $$ /$$/ /$$/\\ $$| $$/$$ $$ /$$ \\ $$ /$$/ /$$/ /$$/
|
||||
\\ $$ /$$$$$$$$| $$ \\ $$| $$$$$$/| $$$$$$//$$/ /$$/ /$$/
|
||||
\\__/|________/|__/ |__/ \\____ $$$ \\______/|__/ |__/ |__/
|
||||
\\__/
|
||||
").lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>();
|
||||
async fn run(&mut self, args: Vec<String>) -> Result<(), application::Error> {
|
||||
|
||||
self.window.set_dimensions(60, 15);
|
||||
self.window.set_position(10, 3);
|
||||
self.window.set_title("Editor");
|
||||
self.window.open();
|
||||
|
||||
if let Some(s) = args.get(0) {
|
||||
self.buffer = s.lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>()
|
||||
}
|
||||
|
||||
loop {
|
||||
// start by rendering the screen
|
||||
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
|
||||
let keystroke = std::io::Stdin::keystroke().await;
|
||||
@@ -203,19 +186,12 @@ impl Application for Editor {
|
||||
KeyStroke::Char('i') => self.mode = Mode::Insert,
|
||||
KeyStroke::Char(':') => self.mode = Mode::Command,
|
||||
KeyStroke::Char('d') => self.mode = Mode::Diff,
|
||||
KeyStroke::Char('`') => {
|
||||
// TODO: End terminal session
|
||||
// ncurses::endwin();
|
||||
return Ok(());
|
||||
}
|
||||
KeyStroke::Char('`') => return Ok(()),
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
Mode::Insert => {
|
||||
match keystroke {
|
||||
KeyStroke::Enter => {
|
||||
// TODO: newline function
|
||||
},
|
||||
KeyStroke::Char(c) => {
|
||||
match c {
|
||||
// escape
|
||||
@@ -247,12 +223,8 @@ impl Application for Editor {
|
||||
KeyStroke::Down => {
|
||||
self.move_cursor(0, 1);
|
||||
},
|
||||
KeyStroke::None => {
|
||||
serial_println!("none");
|
||||
},
|
||||
_ => {
|
||||
serial_println!("other");
|
||||
}
|
||||
KeyStroke::None => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Mode::Command => {
|
||||
@@ -280,11 +252,11 @@ impl Application for Editor {
|
||||
|
||||
impl CgComponent for Editor {
|
||||
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 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 {
|
||||
break;
|
||||
}
|
||||
@@ -297,7 +269,7 @@ impl CgComponent for Editor {
|
||||
|
||||
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))?;
|
||||
}
|
||||
}
|
||||
@@ -317,7 +289,7 @@ impl CgComponent for Editor {
|
||||
let toolbar = line_and_col + " " + &mode + " " + &unsaved;
|
||||
|
||||
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)
|
||||
@@ -328,3 +300,14 @@ impl CgComponent for Editor {
|
||||
}
|
||||
}
|
||||
|
||||
// self.buffer = String::from("
|
||||
// /$$ /$$$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$$ /$$ /$$ /$$
|
||||
// /$$/|_____ $$ | $$ / $$ /$$__ $$| $$____/ /$$/| $$| $$
|
||||
// /$$/ /$$/ | $$/ $$/| $$ \\ $$| $$ /$$/ \\ $$\\ $$
|
||||
// /$$/ /$$/ \\ $$$$/ | $$ | $$| $$$$$$$ /$$/ \\ $$\\ $$
|
||||
// | $$ /$$/ >$$ $$ | $$ | $$|_____ $$ /$$/ /$$/ /$$/
|
||||
// \\ $$ /$$/ /$$/\\ $$| $$/$$ $$ /$$ \\ $$ /$$/ /$$/ /$$/
|
||||
// \\ $$ /$$$$$$$$| $$ \\ $$| $$$$$$/| $$$$$$//$$/ /$$/ /$$/
|
||||
// \\__/|________/|__/ |__/ \\____ $$$ \\______/|__/ |__/ |__/
|
||||
// \\__/
|
||||
// ").lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>();
|
||||
@@ -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),
|
||||
@@ -136,13 +138,6 @@ impl Application for Grapher {
|
||||
entry_widget.update(entry);
|
||||
|
||||
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")))?;
|
||||
}
|
||||
}
|
||||
@@ -156,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),
|
||||
|
||||
@@ -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") {
|
||||
|
||||
|
||||
+226
-13
@@ -1,30 +1,71 @@
|
||||
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 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 {
|
||||
history: Vec<String>,
|
||||
idx: u32,
|
||||
history_idx: usize,
|
||||
|
||||
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]
|
||||
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 {
|
||||
match self.next().await {
|
||||
Err(e) => {
|
||||
self.write(format!("Error: {:?}", e), Color::Yellow);
|
||||
return Err(e);
|
||||
},
|
||||
Ok(exit) => {
|
||||
if exit { return Ok(()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ZxqSH {
|
||||
@@ -32,19 +73,191 @@ impl ZxqSH {
|
||||
|
||||
// update cycle for the shell
|
||||
|
||||
// TOOD: prompt
|
||||
|
||||
// TODO: exit if necessar
|
||||
// TODO: prompt
|
||||
let mut command = self.input().await;
|
||||
// TODO: exit if necessary
|
||||
|
||||
// TODO: execute command
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
+22
-12
@@ -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,
|
||||
}
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,3 @@ pub mod apps;
|
||||
pub mod games;
|
||||
pub mod utils;
|
||||
pub mod shell;
|
||||
pub mod shellrewrite;
|
||||
+36
-28
@@ -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!(
|
||||
|
||||
@@ -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))
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
@@ -49,13 +49,13 @@ 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();
|
||||
// let ds = Display::borrow();
|
||||
|
||||
let os = OS.lock().os.clone();
|
||||
let version = OS.lock().version.clone();
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user