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

This commit is contained in:
2025-02-18 20:05:54 +00:00
parent 1ace354158
commit 1e7d513f26
21 changed files with 369 additions and 309 deletions
+158 -41
View File
@@ -1,4 +1,5 @@
use alloc::{string::String, vec::Vec, boxed::Box};
use alloc::{string::String, vec::Vec, boxed::Box, format};
use alloc::string::ToString;
use core::any::Any;
use crate::std::{application::{Application, Error}, render::Window};
@@ -10,9 +11,10 @@ use crate::apps::grapher::Grapher;
use crate::apps::tasks::Tasks;
use crate::games::gameoflife::GameOfLife;
use crate::games::paper_rs::GameBoard;
use crate::{games, println, utils};
use crate::std::io::{Display, Serial};
use crate::std::render::{ColouredChar, Frame, RenderError};
use crate::{games, println, serial_println, utils};
use crate::std::application::Error::ApplicationError;
use crate::std::io::{Color, ColorCode, Display, KeyStroke, Serial, Stdin};
use crate::std::render::{ColouredChar, Frame, Position, RenderError};
use crate::std::time::timer;
use crate::user::lib::libgui::cg_core::CgComponent;
use crate::utils::crystalfetch::CrystalFetch;
@@ -23,24 +25,44 @@ pub struct ZxqSH {
history: Vec<String>,
history_idx: usize,
row_pos: usize,
col_pos: usize,
window: Window,
buffer: Vec<Vec<ColouredChar>>,
buffer_width: usize,
// the buffer is a vec of coloured characters
// we use a 1d vec so that the terminal can be resized.
buffer: Vec<ColouredChar>,
}
#[async_trait]
impl Application for ZxqSH {
fn new() -> Self {
todo!()
fn new(window: Option<Window>) -> Result<ZxqSH, Error> {
match window {
Some(window) => {
Ok(ZxqSH {
history: Vec::new(),
history_idx: 0,
window,
buffer: Vec::new(),
})
}
None => Err(Error::NoWindow),
}
}
async fn run(&mut self, window: Option<Window>, _args: Vec<String>) -> Result<(), Error> {
async fn run(&mut self, _args: Vec<String>) -> Result<(), Error> {
self.window.set_dimensions(78, 23);
self.window.set_position(1, 1);
self.window.set_title("Terminal");
self.window.open();
loop {
if let Ok(exit) = self.next().await {
if exit { return Ok(()) }
match self.next().await {
Err(e) => {
self.write(format!("Error: {:?}", e), Color::Yellow);
return Err(e);
},
Ok(exit) => {
if exit { return Ok(()) }
}
}
}
}
@@ -52,20 +74,95 @@ impl ZxqSH {
// update cycle for the shell
// TODO: prompt
let command = String::new();
let mut command = self.input().await;
// TODO: exit if necessary
// TODO: execute command
self.execute(command, Vec::new()).await;
// return
if let Err(e) = self.execute(command, Vec::new()).await {
match e {
Error::UnknownCommand(e) => {
self.write("Unknown command\n".to_string(), Color::Yellow);
}
_ => {
self.write(format!("Error: {:?}\n", e), Color::Yellow);
}
}
}
Ok(false)
}
async fn write_char(&mut self, ch: char) {
self.buffer[self.row_pos][self.col_pos] = ColouredChar::new(ch);
fn write(&mut self, string: String, color: Color) {
for ch in string.chars() {
self.write_char(ch, color);
}
}
fn write_char(&mut self, ch: char, color: Color) {
self.buffer.push(ColouredChar::coloured(ch, ColorCode::new(color, Color::Black)));
while self.buffer.len() > 100000 {
self.buffer.remove(0);
}
if let Ok(frame) = self.render() {
self.window.render(&frame).unwrap();
}
}
fn backspace(&mut self) {
let _ = self.buffer.pop();
if let Ok(frame) = self.render() {
self.window.render(&frame).unwrap();
}
}
async fn input(&mut self) -> String {
let mut string = String::new();
self.write("ZxqS> ".to_string(), Color::Cyan);
loop {
let ch = Stdin::keystroke().await;
match ch {
KeyStroke::Char(c) => {
match c {
'\x08' => {
if string.len() == 0 { continue; }
string.pop();
self.backspace()
},
'\n' => {
self.write_char(c, Color::White);
break
},
_ => {
self.write_char(c, Color::White);
string.push(c)
}
}
}
_ => {}
}
}
string
}
fn get_col(&self) -> usize {
let term_width = self.window.dimensions().x as isize;
let mut col = self.buffer.iter().rev().take_while(|c| c.character != '\n').count() as isize;
while col - term_width >= 0 {
col -= term_width;
}
col as usize
}
fn lines(&self) -> Vec<Vec<ColouredChar>> {
self.buffer
.split(|c| c.character == '\n')
.map(|line| line.to_vec())
.collect()
}
async fn execute(&self, cmd: String, args: Vec<String>) -> Result<(), Error> {
@@ -73,11 +170,11 @@ impl ZxqSH {
let window = Window::new();
match cmd.as_str() {
"calculate" | "calc" | "solve" => Calculator::new().run(Some(window), args).await?,
"games/connect4" => crate::user::bin::games::connect4::Game::new().run(Some(window), args).await?,
"rickroll" => Rickroll::new().run(Some(window), args).await?,
"crystalfetch" => CrystalFetch::new().run(Some(window), args).await?,
"tasks" => Tasks::new().run(Some(window), args).await?,
"calculate" | "calc" | "solve" => Calculator::new(Some(window)).expect("couldn't open window").run(args).await?,
"games/connect4" => crate::user::bin::games::connect4::Game::new(Some(window)).expect("couldn't open window").run(args).await?,
"rickroll" => Rickroll::new(Some(window)).expect("couldn't open window").run(args).await?,
"crystalfetch" => CrystalFetch::new(Some(window)).expect("couldn't open window").run(args).await?,
"tasks" => Tasks::new(Some(window)).expect("couldn't open window").run(args).await?,
"VGA" => {
use vga::colors::Color16;
use vga::writers::{GraphicsWriter, Graphics640x480x16};
@@ -86,19 +183,18 @@ impl ZxqSH {
mode.clear_screen(Color16::Black);
mode.draw_line((80, 60), (120, 420), Color16::Cyan);
},
"graph" => Grapher::new().run(Some(window), args).await?,
"games/snake" => games::snake::Game::new().run(Some(window), args).await?,
"games/asteroids" => games::asteroids::Game::new().run(Some(window), args).await?,
"games/pong" => games::pong::Game::new().run(Some(window), args).await?,
"games/paper.rs" => games::paper_rs::GameBoard::new().run(Some(window), args).await?,
"graph" => Grapher::new(Some(window)).expect("couldn't open window").run(args).await?,
"games/snake" => games::snake::Game::new(Some(window)).expect("couldn't open window").run(args).await?,
"games/asteroids" => games::asteroids::Game::new(Some(window)).expect("couldn't open window").run(args).await?,
"games/pong" => games::pong::Game::new(Some(window)).expect("couldn't open window").run(args).await?,
"games/paper.rs" => games::paper_rs::GameBoard::new(Some(window)).expect("couldn't open window").run(args).await?,
"serial" => println!("{}", Serial::reply_char('e')),
"games/gameoflife" => GameOfLife::new().run(Some(window), Vec::new()).await?,
"games/gameoflife" => GameOfLife::new(Some(window)).expect("couldn't open window").run(Vec::new()).await?,
"games/tetris" => {
// games::tetris::TetrisEngine::new().run(Vec::new()).await?;
// games::tetris::TetrisEngine::new().expect("couldn't open window").run(Vec::new()).await?;
}
"gigachad?" => utils::gigachad_detector::GigachadDetector::new().run(Some(window), args).await?,
"editor" => Editor::new().run(Some(window), args).await?,
"gigachad?" => utils::gigachad_detector::GigachadDetector::new(Some(window)).expect("couldn't open window").run(args).await?,
"editor" => Editor::new(Some(window)).expect("couldn't open window").run(args).await?,
// direct OS functions (not applications)
"echo" => {
println!(
@@ -116,6 +212,10 @@ impl ZxqSH {
_ => return Err(Error::UnknownCommand(cmd))
};
if let Ok(frame) = self.render() {
self.window.render(&frame).unwrap();
}
Ok(())
}
}
@@ -126,17 +226,34 @@ impl CgComponent for ZxqSH {
let term_height = self.window.dimensions().y;
let term_width = self.window.dimensions().x;
let buffer_width = self.buffer_width;
let buffer_height = self.buffer.len();
self.window.move_cursor(self.col_pos as i32, term_height as i32)?;
self.window.move_cursor(self.get_col() as i32, term_height as i32 - 1)?;
// render the contents of the terminal to a frame
for (i, row) in self.buffer[buffer_height - term_height..buffer_height].iter().enumerate() {
for (j, col) in row.iter().enumerate().take(term_width) {
frame[i][j] = *col;
let mut line = term_height - 1;
let mut col = self.get_col();
let buff = self.lines();
let mut lines = buff.iter();
for line_chars in lines.rev() {
col = line_chars.len() % term_width;
for c in line_chars.iter().rev() {
if c.character == '\n' { continue; }
frame.write(Position::new(col, line), c.clone())?;
if col <= 0 {
line -= 1;
col = term_width;
}
col -= 1;
}
line -= 1;
}
Ok(frame)
}