diff --git a/src/system/kernel/render.rs b/src/system/kernel/render.rs index e18b720..678fa1d 100644 --- a/src/system/kernel/render.rs +++ b/src/system/kernel/render.rs @@ -52,6 +52,7 @@ pub enum RenderError { InvalidCharacter, InvalidColour, InvalidRenderMode, + Other(&'static str), } impl ScreenChar { @@ -111,19 +112,16 @@ 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]; - - 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, - }; + pub fn render_frame(&mut self, mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer + for (i, row) in frame.iter_mut().enumerate() { + for (j, col) in row.iter_mut().enumerate() { + if let Some(c) = special_char(col.character as char) { + col.character = c as u8; + } } } - self.app_buffer = processed_frame; + self.app_buffer = frame; self.internal_render(); } diff --git a/src/system/kernel/tasks/keyboard.rs b/src/system/kernel/tasks/keyboard.rs index f45908f..02dcc6d 100644 --- a/src/system/kernel/tasks/keyboard.rs +++ b/src/system/kernel/tasks/keyboard.rs @@ -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: () } } diff --git a/src/system/std/render.rs b/src/system/std/render.rs index 1138b3a..1ef9bb7 100644 --- a/src/system/std/render.rs +++ b/src/system/std/render.rs @@ -45,13 +45,12 @@ impl Window { } 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(()) } @@ -165,7 +164,12 @@ impl Window { } Ok(()) } +} +impl Drop for Window { + fn drop(&mut self) { + RENDERER.lock().terminal_mode(); + } } #[derive(Clone, Copy, Debug, PartialEq)] diff --git a/src/user/bin/apps/editor.rs b/src/user/bin/apps/editor.rs index ad08688..5fc6306 100644 --- a/src/user/bin/apps/editor.rs +++ b/src/user/bin/apps/editor.rs @@ -20,7 +20,6 @@ pub struct Editor { command: String, mode: Mode, unsaved: bool, - display: Display, lineno_width: i32, window: Window, } @@ -37,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 "), } } @@ -45,8 +44,6 @@ impl core::fmt::Display for Mode { impl Editor { fn move_cursor(&mut self, dx: i32, dy: i32) { - serial_println!("trying to move"); - if dy != 0 && self.cursor_pos.y + dy >= 0 && self.cursor_pos.y + dy <= self.buffer.len() as i32 @@ -86,14 +83,10 @@ impl Editor { self.offset_pos.y -= 1; } - serial_println!("talking to kernel"); - 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(); - - serial_println!("done talking to kernel"); } fn delete_char(&mut self) { @@ -158,7 +151,6 @@ impl Application for Editor { command: String::new(), mode: Mode::Normal, unsaved: false, - display: Display::borrow(), lineno_width: 0, window: Window::new(), } @@ -173,6 +165,7 @@ impl Application for Editor { self.window.set_dimensions(60, 23); self.window.set_position(10, 1); 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::>>() @@ -195,19 +188,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 diff --git a/src/user/bin/apps/zxqsh.rs b/src/user/bin/apps/zxqsh.rs index ae23ccf..38f740d 100644 --- a/src/user/bin/apps/zxqsh.rs +++ b/src/user/bin/apps/zxqsh.rs @@ -1,15 +1,34 @@ use alloc::{string::String, vec::Vec, boxed::Box}; - +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, utils}; +use crate::std::io::{Display, Serial}; +use crate::std::render::{ColouredChar, Frame, 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, - idx: u32, + history_idx: usize, + + row_pos: usize, + col_pos: usize, window: Window, - + buffer: Vec>, + buffer_width: usize, } #[async_trait] @@ -32,19 +51,96 @@ impl ZxqSH { // update cycle for the shell - // TOOD: prompt + // TODO: prompt + let command = String::new(); - // TODO: exit if necessar + // TODO: exit if necessary // TODO: execute command - + self.execute(command, Vec::new()).await; // return Ok(false) } + async fn write_char(&mut self, ch: char) { + self.buffer[self.row_pos][self.col_pos] = ColouredChar::new(ch); + + } + + async fn execute(&self, cmd: String, args: Vec) -> Result<(), Error> { + + let window = Window::new(); + + match cmd.as_str() { + "calculate" | "calc" | "solve" => Calculator::new().run(Some(window), args).await?, + "games/connect4" => crate::user::bin::games::connect4::Game::new().run(Some(window), args).await?, + "rickroll" => Rickroll::new().run(Some(window), args).await?, + "crystalfetch" => CrystalFetch::new().run(Some(window), args).await?, + "tasks" => Tasks::new().run(Some(window), args).await?, + "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().run(Some(window), args).await?, + "games/snake" => games::snake::Game::new().run(Some(window), args).await?, + "games/asteroids" => games::asteroids::Game::new().run(Some(window), args).await?, + "games/pong" => games::pong::Game::new().run(Some(window), args).await?, + "games/paper.rs" => games::paper_rs::GameBoard::new().run(Some(window), args).await?, + "serial" => println!("{}", Serial::reply_char('e')), + "games/gameoflife" => GameOfLife::new().run(Some(window), Vec::new()).await?, + "games/tetris" => { + // games::tetris::TetrisEngine::new().run(Vec::new()).await?; + } + "gigachad?" => utils::gigachad_detector::GigachadDetector::new().run(Some(window), args).await?, + "editor" => Editor::new().run(Some(window), args).await?, + + // direct OS functions (not applications) + "echo" => { + println!( + "Crystal: '{}'", + args.into_iter() + .map(|mut s| { + s.push_str(" "); + s + }) + .collect::() + ) + } + "clear" => Display::clear(), + "time" => timer(), + _ => return Err(Error::UnknownCommand(cmd)) + }; - async fn execute(&self, command: String) -> Result<(), Error> { Ok(()) } +} + +impl CgComponent for ZxqSH { + fn render(&self) -> Result { + let mut frame = Frame::from_window(&self.window); + + let term_height = self.window.dimensions().y; + let term_width = self.window.dimensions().x; + let buffer_width = self.buffer_width; + let buffer_height = self.buffer.len(); + + self.window.move_cursor(self.col_pos as i32, term_height as i32)?; + + // render the contents of the terminal to a frame + for (i, row) in self.buffer[buffer_height - term_height..buffer_height].iter().enumerate() { + for (j, col) in row.iter().enumerate().take(term_width) { + frame[i][j] = *col; + } + } + Ok(frame) + } + + fn as_any(&self) -> &dyn Any { + self as &dyn Any + } } \ No newline at end of file