use core::fmt; use lazy_static::lazy_static; use spin::{Mutex, MutexGuard}; use crate::hard::vga::{self, Vga}; #[macro_export] macro_rules! print { ($($arg:tt)*) => ($crate::dev::console::print_args(format_args!($($arg)*))); } #[macro_export] macro_rules! println { () => ($crate::print!("\n")); ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); } lazy_static! { static ref OUT: Mutex = Mutex::new(Console::init()); } pub fn out<'r>() -> MutexGuard<'r, Console> { OUT.lock() } pub struct Console { pub cursor: Cursor, pub vga: Vga, } impl Console { pub fn init() -> Self { let cursor = Cursor::new(vga::WIDTH, vga::HEIGHT); let vga = Vga; Self { cursor, vga } } pub fn print_(&mut self, text: &str) { for c in text.chars() { match c { '\n' => self.cursor.ret(), '\t' => self.print_(" "), _ => { self.vga.write_at(self.cursor.pos(), c); self.cursor.progress(); } } } } pub fn correct(&mut self) { self.cursor.set_col((self.cursor.col().max(1) - 1)); self.vga.write_at(self.cursor.pos(), ' '); } } struct Cursor { line: usize, column: usize, width: usize, height: usize, } impl Cursor { pub fn new(width: usize, height: usize) -> Self { Self { line: 0, column: 0, width, height, } } pub fn pos(&self) -> (usize, usize) { (self.column, self.line) } pub fn line(&self) -> usize { self.line } pub fn col(&self) -> usize { self.column } pub fn set_pos(&mut self, pos: (usize, usize)) { (self.column, self.line) = pos; } pub fn set_line(&mut self, line: usize) { self.line = line; } pub fn set_col(&mut self, col: usize) { self.column = col; } pub fn progress(&mut self) { self.column += 1; if self.column < self.width { return; } self.column = 0; self.line += 1; if self.line < self.height { return; } self.line = 0; } pub fn ret(&mut self) { self.column = self.width; self.progress(); } } impl fmt::Write for Console { fn write_str(&mut self, s: &str) -> fmt::Result { self.print_(s); Ok(()) } } pub fn print_args(args: fmt::Arguments) { use core::fmt::Write; use x86_64::instructions::interrupts; interrupts::without_interrupts(|| { OUT.lock().write_fmt(args).unwrap(); }); }