use crate::drivers::io::keyboard::{KeyStroke, get_keystroke_async}; use crate::prelude::*; use crate::resources::font::{FONT_CP850_8X16, FONT_SPLEEN_8X16, Font}; use crate::std::application::frame::Frame; use crate::std::application::render::RenderError; use crate::std::application::window::Window; use crate::std::application::{Application, Error}; use crate::std::ascii::Writer; use crate::std::maths::geometry::Vec2; use alloc::string::ToString; pub struct Editor { cursor_line: usize, cursor_col: usize, mode: Mode, buffer: String, window: Window, } impl Default for Editor { fn default() -> Self { Self::new() } } impl<'a> Editor { const PADDING: usize = 8; pub const fn new() -> Self { Self { cursor_line: 0, cursor_col: 0, mode: Mode::Nor, buffer: String::new(), window: Window::new(), } } fn render(&'a self) -> Result, RenderError> { let mut frame = Frame::new(&self.window); let writer = Writer::new(Font::default()); let (width, height) = writer.font_size().into(); let mut col = Self::PADDING; let mut line = Self::PADDING; let mut scale = 1; for ch in self.buffer.chars() { if ch == '\n' { line += scale * height; col = Self::PADDING; scale = 1; continue; } if width * scale + col > frame.dimensions().x() { line += scale * height; col = Self::PADDING; } writer.render_glyph(&mut frame, Vec2::new(col, line), ch as u8, scale)?; col += scale * width; } Ok(frame) } fn get_lines(&self) -> Vec<&str> { self.buffer.split('\n').collect::>(); todo!() } #[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)] fn move_cursor(&mut self, x: i32, y: i32) { todo!() } #[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)] fn delete_char(&mut self) { todo!() } #[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)] fn insert_char(&mut self, c: char) { todo!() } #[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)] fn splitline(&mut self) { todo!() } } impl Application for Editor { type Output = (); async fn run(&mut self, _args: Vec) -> Result { self.window.set_dimensions(Vec2::new(1280, 800)); self.window.set_position(Vec2::new(0, 0)); self.window.open(); self.buffer = "Hello world, this is a test init. idk test \n ewntuiewi gjk gfdfg gndf ngdfgnmdfg ndfgmndfg gdfndfnkg njkdgjkndfjnkg ngnjfgnfgnfg fgn fn gfj gnfg jnfgjfngjk fgnjfgnjk jnkdgjnkdfg gfnd njkgdfgjn d fjnkgjkndfgjkndfgjn gndfjnk njkgdfng jnkfgdjknd jnfkgnjk".to_string(); loop { if let Err(_err) = self.render().and_then(|frame| frame.render()) { // TODO: Handle error return Err(Error::ApplicationFailed("Rendering failed".to_string())); } let keystroke = get_keystroke_async().await; match self.mode { Mode::Nor => match keystroke { KeyStroke::Char('i') => self.mode = Mode::Ins, KeyStroke::Char('`') => return Ok(()), _ => {} }, Mode::Ins => { match keystroke { KeyStroke::Char(c) => { match c { // escape '\x1B' => self.mode = Mode::Nor, // delete '\x7F' => self.delete_char(), // backspace '\x08' => { self.move_cursor(-1, 0); self.delete_char(); } // enter '\n' => self.splitline(), _ => { self.insert_char(c); self.move_cursor(1, 0); } } } KeyStroke::Left => { self.move_cursor(-1, 0); } KeyStroke::Right => { self.move_cursor(1, 0); } KeyStroke::Up => { self.move_cursor(0, -1); } KeyStroke::Down => { self.move_cursor(0, 1); } KeyStroke::None => {} _ => {} } } } } } } pub enum Mode { Nor, Ins, } impl core::fmt::Display for Mode { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Nor => write!(f, "Normal"), Self::Ins => write!(f, "Insert"), } } }