diff --git a/ableos/assets/balloon.txt b/ableos/assets/balloon.txt index cc015bc4..db61c1e7 100644 --- a/ableos/assets/balloon.txt +++ b/ableos/assets/balloon.txt @@ -1,9 +1,9 @@ - ,-""""-. OS: AbleOS + ,-""""-. OS: $BLUE$AbleOS$RESET$ ,'\ _ _`. Host: ??? / \)_)-)_)-\ Kernel: AKern-{}-v{} : : Uptime: {} \ / Packages: None - \ / Shell: RhaiShell + \ / Shell: BuiltinShell `. ,' Resolution: 640x480 `. ,' Terminal: VGABuffer `.,' CPU: {} diff --git a/ableos/assets/kernel.toml b/ableos/assets/kernel.toml index ae07a949..a7b45af2 100644 --- a/ableos/assets/kernel.toml +++ b/ableos/assets/kernel.toml @@ -6,7 +6,7 @@ user_processes = ["shell"] enabled = true level = "Trace" log_to_serial = true -filter = [] +filter = ["ableos::vterm"] [tests] diff --git a/ableos/src/arch/x86_64/interrupts.rs b/ableos/src/arch/x86_64/interrupts.rs index 5c0d80d7..e08eb07f 100644 --- a/ableos/src/arch/x86_64/interrupts.rs +++ b/ableos/src/arch/x86_64/interrupts.rs @@ -1,6 +1,6 @@ use core::panic::PanicInfo; -use crate::{arch::gdt, rhai_shell::KEYBUFF, VgaBuffer, SCREEN_BUFFER}; +use crate::{arch::gdt, println, rhai_shell::KEYBUFF}; use cpuio::outb; use pic8259::ChainedPics; use qrcode::QrCode; @@ -213,18 +213,6 @@ pub fn reset_pit_for_cpu() { set_pit_3(1000); } pub fn bsod(src: BSODSource) -> ! { - trace!("{src:?}"); - - let mut mode = SCREEN_BUFFER.lock(); - mode.force_redraw(); - /* - for y in 0..480 { - for x in 0..640 { - mode.set_pixel(x, y, 0x0000ff00); - } - } - */ - let mut x = 1; let mut y = 0; @@ -241,20 +229,7 @@ pub fn bsod(src: BSODSource) -> ! { src1 ); - for current in st.chars() { - if current == '\n' || x == 40 { - y += 1; - x = 1; - } else { - mode.draw_char( - (x * 14).try_into().unwrap(), - (y * 22).try_into().unwrap(), - current, - 0xffff0000, - ); - } - x += 1; - } + println!("\n{}", st); let mut x = 1; let mut y = 34; @@ -277,19 +252,7 @@ pub fn bsod(src: BSODSource) -> ! { .module_dimensions(2, 1) .build(); - for current in image.chars() { - if current == '\n' { - y += 1; - x = 0; - } else { - if current == '█' { - mode.draw_filled_rect(x * 6, y * 7, (x * 6) + 6, (y * 7) + 7, 0xffffff00); - } - } - x += 1; - } - - mode.copy_to_buffer(); + println!("{}", image); sloop(); } diff --git a/ableos/src/graphics/mod.rs b/ableos/src/graphics/mod.rs index 74874ef5..b34aa8bd 100644 --- a/ableos/src/graphics/mod.rs +++ b/ableos/src/graphics/mod.rs @@ -1,16 +1,3 @@ -use ab_glyph::{Font, FontRef, Glyph}; -use shadeable::{ - evaluate_shader, - pixel_format::{get_b, get_g, get_r, Rgba64}, -}; -use spin::Lazy; -use vga::{colors::Color16, writers::GraphicsWriter}; - -use crate::vga_e::VGAE; - -pub static SCREEN_BUFFER: Lazy> = - Lazy::new(|| spin::Mutex::new(ScreenBuffer::new(640, 480))); - const FONT_SCALE: f32 = 1.6; const GLYPH_HEIGHT: f32 = 18.0; @@ -134,76 +121,6 @@ impl ScreenBuffer { vga.set_mode(); vga.clear_screen(vga::colors::Color16::Black); } - - /// Draw a glyph on the screen at the given position - /// - /// # Arguments - /// * `x` - the x position of the glyph - /// * `y` - the y position of the glyph - /// * `glyph` - the glyph to draw - /// * `color` - the color of the glyph - pub fn draw_char(&mut self, mut x: u32, mut y: u32, character: char, color: Rgba64) { - // trace!["Judy Hopps is thicc af"]; - // let mode = *VGAE.lock(); - // trace!["She got them bouncy bunny buns"]; - - let basic_multingual_plane = FontRef::try_from_slice(include_bytes!( - "../../../ableos/assets/fonts/unifont-14.0.01.ttf" - )) - .unwrap(); - - let supplementary_multilingual_plane = FontRef::try_from_slice(include_bytes!( - "../../../ableos/assets/fonts/unifont_upper-14.0.01.ttf" - )) - .unwrap(); - - // let mut has_char = false; - // for x in font.codepoint_ids() { - // if x.1 == character { - // has_char = true; - // break; - // } - // } - - let in_supp_plane = character as u32 > 0xffff; - - let plane = match in_supp_plane { - false => basic_multingual_plane, - true => supplementary_multilingual_plane, - }; - - match character { - '\n' => { - // x = 0; - // y += (GLYPH_HEIGHT * FONT_SCALE) as u32; - } - _ => { - let q_glyph: Glyph = plane.glyph_id(character).with_scale_and_position( - 20.0 * FONT_SCALE, - ab_glyph::point(GLYPH_WIDTH * FONT_SCALE, GLYPH_HEIGHT * FONT_SCALE), - ); - - // elf: I don't know if GLYPH_HEIGHT is in the right units here. I'm just guessing. - if x as usize > self.size.x { - x = 0; - y += (GLYPH_HEIGHT * FONT_SCALE) as u32; - } - - if let Some(q) = plane.outline_glyph(q_glyph) { - q.draw(|gx, gy, c| { - if c > 0.0015 { - let corner = q.px_bounds().min; - self.set_pixel( - gx as usize + corner.x as usize + x as usize, - gy as usize + corner.y as usize + y as usize, - color, - ); - } - }); - } - } - } - } } pub fn get_coordinates(x1: i32, y1: i32, x2: i32, y2: i32) -> Vec<(usize, usize)> { @@ -341,3 +258,74 @@ pub fn into_vga_16(rgba_64: Rgba64) -> Color16 { (High, High, High) => White, } } + +// TODO: Incorporate this into the ableos vga crate +/// Draw a glyph on the screen at the given position +/// +/// # Arguments +/// * `x` - the x position of the glyph +/// * `y` - the y position of the glyph +/// * `glyph` - the glyph to draw +/// * `color` - the color of the glyph +pub fn draw_char(&mut self, mut x: u32, mut y: u32, character: char, color: Rgba64) { + // trace!["Judy Hopps is thicc af"]; + // let mode = *VGAE.lock(); + // trace!["She got them bouncy bunny buns"]; + + let basic_multingual_plane = FontRef::try_from_slice(include_bytes!( + "../../../ableos/assets/fonts/unifont-14.0.01.ttf" + )) + .unwrap(); + + let supplementary_multilingual_plane = FontRef::try_from_slice(include_bytes!( + "../../../ableos/assets/fonts/unifont_upper-14.0.01.ttf" + )) + .unwrap(); + + // let mut has_char = false; + // for x in font.codepoint_ids() { + // if x.1 == character { + // has_char = true; + // break; + // } + // } + + let in_supp_plane = character as u32 > 0xffff; + + let plane = match in_supp_plane { + false => basic_multingual_plane, + true => supplementary_multilingual_plane, + }; + + match character { + '\n' => { + // x = 0; + // y += (GLYPH_HEIGHT * FONT_SCALE) as u32; + } + _ => { + let q_glyph: Glyph = plane.glyph_id(character).with_scale_and_position( + 20.0 * FONT_SCALE, + ab_glyph::point(GLYPH_WIDTH * FONT_SCALE, GLYPH_HEIGHT * FONT_SCALE), + ); + + // elf: I don't know if GLYPH_HEIGHT is in the right units here. I'm just guessing. + if x as usize > self.size.x { + x = 0; + y += (GLYPH_HEIGHT * FONT_SCALE) as u32; + } + + if let Some(q) = plane.outline_glyph(q_glyph) { + q.draw(|gx, gy, c| { + if c > 0.0015 { + let corner = q.px_bounds().min; + self.set_pixel( + gx as usize + corner.x as usize + x as usize, + gy as usize + corner.y as usize + y as usize, + color, + ); + } + }); + } + } + } +} diff --git a/ableos/src/lib.rs b/ableos/src/lib.rs index 99600f06..b2995995 100644 --- a/ableos/src/lib.rs +++ b/ableos/src/lib.rs @@ -47,7 +47,7 @@ pub mod devices; pub mod driver_traits; pub mod experiments; pub mod filesystem; -pub mod graphics; +// pub mod graphics; pub mod kernel_state; pub mod keyboard; pub mod kmain; diff --git a/ableos/src/print.rs b/ableos/src/print.rs index 6b7724c5..805ad50f 100644 --- a/ableos/src/print.rs +++ b/ableos/src/print.rs @@ -42,7 +42,7 @@ impl core::fmt::Write for Stdout { // x86_64::instructions::interrupts::without_interrupts(|| { let mut term = TERM.lock(); term.set_dirty(true); - term.print(s.to_string()); + term.print(s); drop(term); // }); // trace!("Finished printing"); diff --git a/ableos/src/scratchpad.rs b/ableos/src/scratchpad.rs index 7180b463..0542695b 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -117,7 +117,8 @@ pub fn real_shell() { loop { match x86_64::instructions::interrupts::without_interrupts(|| KEYBUFF.lock().pop()) { Some('\n') => { - println!(); + // panic!(); + // println!(); // match engine.eval_with_scope::(&mut scope, &buf) { // Ok(o) => println!("{o}"), @@ -177,6 +178,11 @@ pub fn command_parser(user: String, command: String) { println!("{}", dir_entry.file_name_string()); } } + + "echo" => { + echo_file(iter.next().unwrap().to_string(), fs); + } + "quit" => shutdown(), _ => { @@ -254,3 +260,27 @@ pub fn list_files_in_dir( entry_list } + +pub static CURRENT_DIR: Lazy> = Lazy::new(|| spin::Mutex::new("/".to_string())); + +pub fn echo_file(path: String, fs: &Synced>>) { + let mut current_dir = CURRENT_DIR.lock(); + + current_dir.push_str(&path); + + let file = fs + .open(current_dir.as_bytes(), OpenOptions::new().read(true)) + .unwrap(); + + if file.is_dir() { + // println!("{} is a directory", path); + } else { + let mut file_contents = Vec::new(); + + let _ret = file.read_to_end(&mut file_contents).unwrap(); + + let file_contents_str = String::from_utf8_lossy(&file_contents); + + println!("{}", file_contents_str); + } +} diff --git a/ableos/src/vterm.rs b/ableos/src/vterm.rs index d5d3da2c..48cfe399 100644 --- a/ableos/src/vterm.rs +++ b/ableos/src/vterm.rs @@ -1,4 +1,5 @@ use crate::{hardware::MOUSE, vga_e::VGAE}; +use logos::{Lexer, Logos}; use vga::{colors::Color16, writers::GraphicsWriter}; const TERM_MINUS_ONE_LINE: usize = 4720; @@ -7,7 +8,7 @@ const CURSOR_COLOR: Color16 = Color16::Cyan; #[derive(Debug)] pub struct Term { dirty: bool, - term: [char; 80 * 60], + term: [(char, Color16); 80 * 60], x: u8, } impl Term { @@ -19,7 +20,7 @@ impl Term { Self { dirty: false, x: 0, - term: ['\0'; 80 * 60], + term: [('\0', Color16::LightGrey); 80 * 60], } } pub fn is_dirty(&self) -> bool { @@ -30,7 +31,7 @@ impl Term { self.dirty = dirty } - pub fn print(&mut self, data: String) { + pub fn print(&mut self, data: &str) { for c in data.chars() { if self.x == 79 { self.move_up(); @@ -45,7 +46,7 @@ impl Term { } trace!("BACKSPACE"); self.x -= 1; - self.term[TERM_MINUS_ONE_LINE + (self.x as usize)] = '\0'; + self.term[TERM_MINUS_ONE_LINE + (self.x as usize)] = ('\0', Color16::LightGrey); } '\n' => { self.move_up(); @@ -53,16 +54,81 @@ impl Term { } c => { - self.term[TERM_MINUS_ONE_LINE + (self.x as usize)] = c; + self.term[TERM_MINUS_ONE_LINE + (self.x as usize)] = (c, Color16::White); self.x += 1; } } } } + // TODO:DEADLOCK: Fix this up + pub fn cprint(&mut self, data: &str) { + let lex = Token::lexer(data); + + trace!("{:?}", lex); + + let mut color = Color16::Red; + for toke in lex { + match toke { + Token::Error => + // unsafe { asm!("int 54") }, + {} + Token::TBlack => color = Color16::Black, + Token::TBlue => { + color = Color16::Blue; + trace!(""); + } + Token::TGreen => color = Color16::Green, + Token::TCyan => color = Color16::Cyan, + Token::TRed => color = Color16::Red, + Token::TMagenta => color = Color16::Magenta, + Token::TBrown => color = Color16::Brown, + Token::TLightGrey => color = Color16::LightGrey, + Token::TDarkGrey => color = Color16::DarkGrey, + Token::TLightBlue => color = Color16::LightBlue, + Token::TLightGreen => color = Color16::LightGreen, + Token::TLightCyan => color = Color16::LightCyan, + Token::TLightRed => color = Color16::LightRed, + Token::TPink => color = Color16::Pink, + Token::TYellow => color = Color16::Yellow, + Token::TWhite => color = Color16::White, + Token::Text(st) => { + for c in st.chars() { + if self.x == 79 { + self.move_up(); + return; + } + + match c { + '\u{08}' => { + if self.x == 0 { + // trace!("IMPOSSIBLE BACKSPACE"); + return; + } + trace!("BACKSPACE"); + self.x -= 1; + self.term[TERM_MINUS_ONE_LINE + (self.x as usize)] = + ('\0', Color16::LightGrey); + } + '\n' => { + self.move_up(); + self.x = 0; + } + + c => { + self.term[TERM_MINUS_ONE_LINE + (self.x as usize)] = (c, color); + self.x += 1; + } + } + } + } + } + } + } + pub fn move_up(&mut self) { self.term.rotate_left(80); for x in 0..80 { - self.term[TERM_MINUS_ONE_LINE + x] = '\0'; + self.term[TERM_MINUS_ONE_LINE + x] = ('\0', Color16::LightGrey); } self.x = 0; } @@ -105,7 +171,7 @@ impl Term { let mut y = 0; for c in self.term { - mode.draw_character(x * 8, y * 8, c, White); + mode.draw_character(x * 8, y * 8, c.0, c.1); if x == 79 { y += 1; x = 0; @@ -119,3 +185,75 @@ impl Term { } } } + +#[derive(Logos, Debug, Clone, PartialEq)] +pub enum Token { + #[regex(r"[\t\n\f]+", logos::skip)] + #[error] + Error, + + #[token("$BLACK$")] + TBlack, + #[token("$BLUE$")] + TBlue, + #[token("$GREEN$")] + TGreen, + #[token("$CYAN$")] + TCyan, + #[token("$RED$")] + TRed, + #[token("$MAGENTA$")] + TMagenta, + #[token("$BROWN$")] + TBrown, + #[token("$LIGHTGREY$")] + TLightGrey, + #[token("$DARKGREY$")] + TDarkGrey, + #[token("$LIGHTBLUE$")] + TLightBlue, + #[token("$LIGHTGREEN$")] + TLightGreen, + #[token("$LIGHTCYAN$")] + TLightCyan, + #[token("$LIGHTRED$")] + TLightRed, + #[token("$PINK$")] + TPink, + #[token("$YELLOW$")] + TYellow, + #[token("$WHITE$")] + TWhite, + + #[regex("/[\x00-\x7F]/", text_lex)] + Text(String), +} + +fn text_lex(lex: &mut Lexer) -> String { + lex.slice().into() +} + +impl Into for Token { + fn into(self) -> Color16 { + match self { + Token::Error => todo!(), + Token::TBlack => Color16::Black, + Token::TBlue => Color16::Blue, + Token::TGreen => Color16::Green, + Token::TCyan => Color16::Cyan, + Token::TRed => Color16::Red, + Token::TMagenta => Color16::Magenta, + Token::TBrown => Color16::Brown, + Token::TLightGrey => Color16::LightGrey, + Token::TDarkGrey => Color16::DarkGrey, + Token::TLightBlue => Color16::LightBlue, + Token::TLightGreen => Color16::LightGreen, + Token::TLightCyan => Color16::LightCyan, + Token::TLightRed => Color16::LightRed, + Token::TPink => Color16::Pink, + Token::TYellow => Color16::Yellow, + Token::TWhite => Color16::White, + Token::Text(_) => todo!(), + } + } +}