progress on terminal app
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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: () }
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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::<Vec<Vec<char>>>()
|
||||
@@ -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
|
||||
|
||||
+103
-7
@@ -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<String>,
|
||||
idx: u32,
|
||||
history_idx: usize,
|
||||
|
||||
row_pos: usize,
|
||||
col_pos: usize,
|
||||
|
||||
window: Window,
|
||||
|
||||
buffer: Vec<Vec<ColouredChar>>,
|
||||
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<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(())
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user