progress on terminal app

This commit is contained in:
2025-02-18 12:34:03 +00:00
parent 41a6b6740b
commit 1ace354158
5 changed files with 129 additions and 42 deletions
+8 -10
View File
@@ -52,6 +52,7 @@ pub enum RenderError {
InvalidCharacter, InvalidCharacter,
InvalidColour, InvalidColour,
InvalidRenderMode, InvalidRenderMode,
Other(&'static str),
} }
impl ScreenChar { impl ScreenChar {
@@ -111,19 +112,16 @@ 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_mut().enumerate() {
for (j, col) in row.iter_mut().enumerate() {
for (i, row) in frame.iter().enumerate() { if let Some(c) = special_char(col.character as char) {
for (j, col) in row.iter().enumerate() { col.character = c as u8;
processed_frame[i][j] = match special_char(col.character as char) { }
Some(c) => ScreenChar::new(c as u8, col.colour),
None => *col,
};
} }
} }
self.app_buffer = processed_frame; self.app_buffer = frame;
self.internal_render(); self.internal_render();
} }
+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: () }
} }
+10 -6
View File
@@ -45,13 +45,12 @@ impl Window {
} }
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(())
} }
@@ -165,7 +164,12 @@ impl Window {
} }
Ok(()) Ok(())
} }
}
impl Drop for Window {
fn drop(&mut self) {
RENDERER.lock().terminal_mode();
}
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
+3 -17
View File
@@ -20,7 +20,6 @@ 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, window: Window,
} }
@@ -37,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 "),
} }
} }
@@ -45,8 +44,6 @@ impl core::fmt::Display for Mode {
impl Editor { impl Editor {
fn move_cursor(&mut self, dx: i32, dy: i32) { fn move_cursor(&mut self, dx: i32, dy: i32) {
serial_println!("trying to move");
if dy != 0 if dy != 0
&& self.cursor_pos.y + dy >= 0 && self.cursor_pos.y + dy >= 0
&& self.cursor_pos.y + dy <= self.buffer.len() as i32 && self.cursor_pos.y + dy <= self.buffer.len() as i32
@@ -86,14 +83,10 @@ impl Editor {
self.offset_pos.y -= 1; self.offset_pos.y -= 1;
} }
serial_println!("talking to kernel");
self.window.move_cursor( self.window.move_cursor(
self.cursor_pos.x - self.offset_pos.x + self.lineno_width + 2, self.cursor_pos.x - self.offset_pos.x + self.lineno_width + 2,
self.cursor_pos.y - self.offset_pos.y self.cursor_pos.y - self.offset_pos.y
).unwrap(); ).unwrap();
serial_println!("done talking to kernel");
} }
fn delete_char(&mut self) { fn delete_char(&mut self) {
@@ -158,7 +151,6 @@ impl Application for Editor {
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: Window::new(), window: Window::new(),
} }
@@ -173,6 +165,7 @@ impl Application for Editor {
self.window.set_dimensions(60, 23); self.window.set_dimensions(60, 23);
self.window.set_position(10, 1); self.window.set_position(10, 1);
self.window.set_title("Editor"); self.window.set_title("Editor");
self.window.open();
if let Some(s) = args.get(0) { if let Some(s) = args.get(0) {
self.buffer = s.lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>() self.buffer = s.lines().map(|l| l.chars().collect()).collect::<Vec<Vec<char>>>()
@@ -195,19 +188,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
+103 -7
View File
@@ -1,15 +1,34 @@
use alloc::{string::String, vec::Vec, boxed::Box}; use alloc::{string::String, vec::Vec, boxed::Box};
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, 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 { pub struct ZxqSH {
history: Vec<String>, history: Vec<String>,
idx: u32, history_idx: usize,
row_pos: usize,
col_pos: usize,
window: Window, window: Window,
buffer: Vec<Vec<ColouredChar>>,
buffer_width: usize,
} }
#[async_trait] #[async_trait]
@@ -32,19 +51,96 @@ impl ZxqSH {
// update cycle for the shell // update cycle for the shell
// TOOD: prompt // TODO: prompt
let command = String::new();
// TODO: exit if necessar // TODO: exit if necessary
// TODO: execute command // TODO: execute command
self.execute(command, Vec::new()).await;
// return // return
Ok(false) 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<String>) -> 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::<String>()
)
}
"clear" => Display::clear(),
"time" => timer(),
_ => return Err(Error::UnknownCommand(cmd))
};
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;
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
}
} }