Supressed clippy errors and add some rust docs
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
/* use core::fmt;
|
||||
use spin::{Lazy, Mutex};
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
use super::framebuffer::{colour::Colour, display::FRAMEBUFFER_WRITER};
|
||||
|
||||
// use crate::resources::font::{FONT_SPLEEN_8X16, Font};
|
||||
|
||||
static FONT_WIDTH: u32 = 8;
|
||||
static FONT_HEIGHT: u32 = 16;
|
||||
|
||||
pub static WRITER: Lazy<Mutex<Writer>> = Lazy::new(|| Mutex::new(Writer::new()));
|
||||
|
||||
pub fn screensize_chars() -> (u32, u32) {
|
||||
let writer = WRITER.lock();
|
||||
(writer.screen_width, writer.screen_height)
|
||||
}
|
||||
|
||||
pub struct Writer {
|
||||
font: &'static Font,
|
||||
/// Measured in chars not pixels.
|
||||
screen_width: u32,
|
||||
/// Measured in chars not pixels.
|
||||
screen_height: u32,
|
||||
/// 16 pixels tall.
|
||||
text_line: u32,
|
||||
/// 8 pixels wide.
|
||||
text_col: u32,
|
||||
|
||||
fg_color: Colour,
|
||||
bg_color: Colour,
|
||||
}
|
||||
|
||||
impl Default for Writer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
pub fn new() -> Self {
|
||||
FRAMEBUFFER_WRITER.lock().as_mut().map_or_else(
|
||||
|| {
|
||||
panic!("Framebuffer writer not initialized.");
|
||||
},
|
||||
|writer| Self {
|
||||
font: &FONT_SPLEEN_8X16,
|
||||
screen_width: writer.width() / 8,
|
||||
screen_height: writer.height() / 16,
|
||||
text_line: 0,
|
||||
text_col: 0,
|
||||
fg_color: Colour::White,
|
||||
bg_color: Colour::Black,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub const fn set_font(&mut self, font: &'static Font) {
|
||||
self.font = font;
|
||||
}
|
||||
|
||||
/// This is sent when the user types a backspace.
|
||||
const BACKSPACE: u8 = 8;
|
||||
|
||||
pub fn write_glyph(&mut self, c: u8) {
|
||||
if c == b'\n' {
|
||||
self.newline();
|
||||
return;
|
||||
} else if c == Self::BACKSPACE {
|
||||
self.backspace();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the character data from the font array. -- each byte is a row of pixels
|
||||
let data: &[u8] = self.font.glyph_for(c as u16);
|
||||
|
||||
if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() {
|
||||
for (row, line) in data.iter().enumerate().take(16) {
|
||||
for col in 0..8 {
|
||||
let pixel_x: u32 = self.text_col * FONT_WIDTH + col;
|
||||
let pixel_y: u32 = self.text_line * FONT_HEIGHT + row as u32;
|
||||
|
||||
if line & (0x80 >> col) != 0 {
|
||||
// Write the foreground color
|
||||
writer.write_pixel(pixel_x as usize, pixel_y as usize, self.fg_color);
|
||||
} else {
|
||||
// Write the background color
|
||||
writer.write_pixel(pixel_x as usize, pixel_y as usize, self.bg_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go to next position
|
||||
if self.text_col + 1 >= self.screen_width {
|
||||
self.newline();
|
||||
} else {
|
||||
self.text_col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn dimensions(&self) -> (u32, u32) {
|
||||
(self.screen_width, self.screen_height)
|
||||
}
|
||||
|
||||
pub const fn next_char(&mut self) {
|
||||
self.text_col += 1;
|
||||
}
|
||||
|
||||
pub const fn newline(&mut self) {
|
||||
self.text_col = 0;
|
||||
|
||||
if self.text_line + 1 >= self.screen_height {
|
||||
self.text_line = 0;
|
||||
} else {
|
||||
self.text_line += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the backspace character. TODO: Implement VT-100 style terminal control
|
||||
/// codes alongside a shell. Not simple.
|
||||
pub fn backspace(&mut self) {
|
||||
if self.text_col > 0 {
|
||||
self.text_col -= 1;
|
||||
// Blank out the previous char.
|
||||
self.write_glyph(b' ');
|
||||
self.text_col -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_string(&mut self, s: &str) {
|
||||
for c in s.chars() {
|
||||
self.write_glyph(c as u8);
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn set_colour(&mut self, fg: Colour, bg: Colour) {
|
||||
self.fg_color = fg;
|
||||
self.bg_color = bg;
|
||||
}
|
||||
|
||||
pub const fn reset_colour(&mut self) {
|
||||
self.fg_color = Colour::White;
|
||||
self.bg_color = Colour::Black;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Write for Writer {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
self.write_string(s);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write(args: fmt::Arguments, fg: Colour, bg: Colour) {
|
||||
use core::fmt::Write;
|
||||
|
||||
interrupts::without_interrupts(|| {
|
||||
let mut writer = WRITER.lock();
|
||||
writer.set_colour(fg, bg);
|
||||
writer.write_fmt(args).unwrap();
|
||||
writer.reset_colour();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
write(args, Colour::White, Colour::Black);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _print_err(args: fmt::Arguments) {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
write(args, Colour::Red, Colour::Black);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _print_log(args: fmt::Arguments) {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
write(args, Colour::Yellow, Colour::Black);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn clear_screen() {
|
||||
interrupts::without_interrupts(|| {
|
||||
let mut writer = WRITER.lock();
|
||||
writer.text_line = 0;
|
||||
writer.text_col = 0;
|
||||
|
||||
if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() {
|
||||
writer.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn reset_cursor() {
|
||||
interrupts::without_interrupts(|| {
|
||||
let mut writer = WRITER.lock();
|
||||
writer.text_line = 0;
|
||||
writer.text_col = 0;
|
||||
});
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println_log {
|
||||
() => ($crate::print_log!("\n"));
|
||||
($($arg:tt)*) => ($crate::print_log!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print_log {
|
||||
($($arg:tt)*) => ($crate::_print_log(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
() => ($crate::print!("\n"));
|
||||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => ($crate::_print(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! printlnerr {
|
||||
() => ($crate::printerr!("\n"));
|
||||
($($arg:tt)*) => ($crate::printerr!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! printerr {
|
||||
($($arg:tt)*) => ($crate::_print_err(format_args!($($arg)*)));
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,64 @@
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
// Some predefined colours as well as custom colours in the proper format. This
|
||||
// assumes that the framebuffer uses 32bpp, something which we will assert on
|
||||
// initialisation.
|
||||
pub enum Colour {
|
||||
Argb(u8, u8, u8, u8),
|
||||
Rgb(u8, u8, u8),
|
||||
HexARGB(u32),
|
||||
Black = 0x000000FF,
|
||||
Blue = 0x0000FFFF,
|
||||
Green = 0x00FF00FF,
|
||||
Cyan = 0x00FFFFFF,
|
||||
Red = 0xFF0000FF,
|
||||
Magenta = 0xFF00FFFF,
|
||||
Yellow = 0xFFFF00FF,
|
||||
White = 0xFFFFFFFF,
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::use_self,
|
||||
reason = "Self is uglier and more verbose than `u32`"
|
||||
)]
|
||||
impl From<Colour> for u32 {
|
||||
fn from(val: Colour) -> Self {
|
||||
match val {
|
||||
Colour::Argb(a, r, g, b) => {
|
||||
(a as u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | (b as u32)
|
||||
}
|
||||
Colour::Rgb(r, g, b) => {
|
||||
((r as u32) << 16) | (g as u32) << 8 | (b as u32)
|
||||
}
|
||||
Colour::HexARGB(hex) => hex,
|
||||
Colour::Black => 0xFF000000,
|
||||
Colour::Blue => 0xFF0000FF,
|
||||
Colour::Green => 0xFF00FF00,
|
||||
Colour::Cyan => 0xFF00FFFF,
|
||||
Colour::Red => 0xFFFF0000,
|
||||
Colour::Magenta => 0xFFFF00FF,
|
||||
Colour::Yellow => 0xFFFFFF00,
|
||||
Colour::White => 0xFFFFFFFF,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Colour {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::Argb(r, g, b, a) => {
|
||||
write!(f, "RGBA(#{:x}{:x}{:x}{:x})", r, g, b, a)
|
||||
}
|
||||
Self::Rgb(r, g, b) => write!(f, "RGB(#{:x}{:x}{:x})", r, g, b),
|
||||
Self::HexARGB(hex) => write!(f, "Hex(#{:x})", hex),
|
||||
Self::Black => write!(f, "Black"),
|
||||
Self::Blue => write!(f, "Blue"),
|
||||
Self::Green => write!(f, "Green"),
|
||||
Self::Cyan => write!(f, "Cyan"),
|
||||
Self::Red => write!(f, "Red"),
|
||||
Self::Magenta => write!(f, "Magenta"),
|
||||
Self::Yellow => write!(f, "Yellow"),
|
||||
Self::White => write!(f, "White"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#![allow(unused)]
|
||||
use libm::include_font;
|
||||
|
||||
pub const FONT_SPLEEN_8X16: Font =
|
||||
Font::new(include_font!("../../resources/font/spleen-8x16.psf"));
|
||||
|
||||
pub const FONT_CP850_8X16: Font =
|
||||
Font::new(include_font!("../../resources/font/cp850-8x16.psf"));
|
||||
|
||||
pub struct Font {
|
||||
width: usize,
|
||||
height: usize,
|
||||
length: u16,
|
||||
data: [[u8; 16]; 512],
|
||||
}
|
||||
|
||||
impl Font {
|
||||
pub const fn new(data: [[u8; 16]; 512]) -> Self {
|
||||
Self {
|
||||
width: 8,
|
||||
height: 16,
|
||||
length: data.len() as u16,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn glyph_for(&self, c: u16) -> &[u8] {
|
||||
if c > self.length {
|
||||
return &self.data[0];
|
||||
}
|
||||
|
||||
&self.data[c as usize]
|
||||
}
|
||||
|
||||
pub const fn width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub const fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub const fn default() -> &'static Self {
|
||||
&FONT_SPLEEN_8X16
|
||||
}
|
||||
}
|
||||
@@ -1 +1,158 @@
|
||||
//! Handles
|
||||
//! Handles setting up the framebuffer passed to us by Limine.
|
||||
#![expect(unused)]
|
||||
use crate::DEFAULT_FONT;
|
||||
|
||||
use super::{colour::Colour, font::Font};
|
||||
|
||||
use limine::framebuffer::Framebuffer;
|
||||
use limine::request::FramebufferRequest;
|
||||
use spin::{Lazy, Mutex};
|
||||
|
||||
#[used]
|
||||
#[unsafe(link_section = ".requests")]
|
||||
/// The Limine framebuffer request.
|
||||
static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
|
||||
|
||||
/// A mutex used for writing to the framebuffer, in most cases we can abstract
|
||||
/// this behind calls to println! etc.
|
||||
pub static FRAMEBUFFER_WRITER: Lazy<Mutex<Option<FramebufferWriter>>> = Lazy::new(
|
||||
|| {
|
||||
Mutex::new(FRAMEBUFFER_REQUEST.get_response().map_or_else(
|
||||
|| {
|
||||
unreachable!("Framebuffer request failed, got None.");
|
||||
},
|
||||
|framebuffer_response| {
|
||||
let framebuffer =
|
||||
framebuffer_response.framebuffers().next()
|
||||
.expect("Expected to find at least one framebuffer in response, got zero.");
|
||||
Some(FramebufferWriter::new(framebuffer, Colour::Black))
|
||||
},
|
||||
))
|
||||
},
|
||||
);
|
||||
|
||||
/// The updated writer stores necessary fields from the [Framebuffer].
|
||||
/// This ensures that the contained types are Send, as Framebuffer was
|
||||
/// not marked as Send.
|
||||
///
|
||||
/// It also avoids the requirement for lifetimes.
|
||||
///
|
||||
/// Note this does not implement Writer as these functions only handle drawing
|
||||
/// pixels.
|
||||
pub struct FramebufferWriter {
|
||||
pitch: u64,
|
||||
/// Number of bits used per pixel, we expect 32 so this will be asserted
|
||||
/// when we initialise the framebuffer.
|
||||
bpp: u16,
|
||||
/// A raw pointer to the framebuffer.
|
||||
addr: *mut u8,
|
||||
/// The width of the screen in pixels.
|
||||
width: u64,
|
||||
/// The height of the screen in pixels.
|
||||
height: u64,
|
||||
/// The default background colour of the Framebuffer.
|
||||
background_colour: Colour,
|
||||
}
|
||||
|
||||
/// Marker trait required for sending the writer across threads, which will
|
||||
/// probably come in handy later.
|
||||
unsafe impl Send for FramebufferWriter {}
|
||||
/// Marker trait required for sharing the writer across threads, which will
|
||||
/// probably come in handy later.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// We wrap this in a Mutex later so this should handle synchronising accesses.
|
||||
unsafe impl Sync for FramebufferWriter {}
|
||||
|
||||
impl FramebufferWriter {
|
||||
/// Creates a new [`FramebufferWriter`] with the specified background
|
||||
/// colour.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the bits per pixel for the framebuffer is not 32 bits per
|
||||
/// pixel, because we didn't exactly handle other cases.
|
||||
pub fn new(framebuffer: Framebuffer, background_colour: Colour) -> Self {
|
||||
// We don't handle other cases, this should not trigger on most newer
|
||||
// hardware.
|
||||
assert!(framebuffer.bpp() == 32);
|
||||
|
||||
Self {
|
||||
pitch: framebuffer.pitch(),
|
||||
bpp: framebuffer.bpp(),
|
||||
addr: framebuffer.addr(),
|
||||
width: framebuffer.width(),
|
||||
height: framebuffer.height(),
|
||||
background_colour,
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a pixel with `colour` to the screen at the given `(x, y)`
|
||||
/// coordinates (in pixels).
|
||||
pub fn write_pixel(&self, x: usize, y: usize, colour: Colour) {
|
||||
let pitch = self.pitch as usize;
|
||||
let bpp = (self.bpp / 8) as usize;
|
||||
let pixel_offset = y * pitch + x * bpp;
|
||||
|
||||
// Safety: We assume the pointer to the framebuffer is valid, which it likely
|
||||
// is because we copy it from the Limine request.
|
||||
unsafe {
|
||||
*(self.addr.add(pixel_offset) as *mut u32) = colour.into();
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a 2D slice `buffer` to the screen. This should be less than the
|
||||
/// size of the screen in dimensions, but does not neccessarily fill the
|
||||
/// whole screen.
|
||||
pub fn render_frame(&self, buffer: &[&[Colour]]) {
|
||||
// TODO: this should return errors.
|
||||
for (y, &row) in buffer.iter().enumerate() {
|
||||
if y >= self.height() as usize {
|
||||
break;
|
||||
}
|
||||
for (x, pixel) in row.iter().enumerate() {
|
||||
if x >= self.width() as usize {
|
||||
break;
|
||||
}
|
||||
self.write_pixel(x, y, *pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the width of the framebuffer in pixels.
|
||||
pub const fn width(&self) -> u32 {
|
||||
self.width as u32
|
||||
}
|
||||
|
||||
/// Returns the height of the framebuffer in pixels.
|
||||
pub const fn height(&self) -> u32 {
|
||||
self.height as u32
|
||||
}
|
||||
|
||||
/// Sets the new default background colour.
|
||||
pub const fn set_default_background_colour(&mut self, bg: Colour) {
|
||||
self.background_colour = bg;
|
||||
}
|
||||
|
||||
/// Clears the screen and sets the background to the default colour.
|
||||
pub fn clear(&self) {
|
||||
let width = self.width as usize;
|
||||
let height = self.height as usize;
|
||||
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
// Write the background in the preferred background colour.
|
||||
self.write_pixel(x, y, self.background_colour);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the screen size in pixels or (0, 0) if something went wrong.
|
||||
pub fn screensize_px() -> (u32, u32) {
|
||||
FRAMEBUFFER_WRITER
|
||||
.lock()
|
||||
.as_mut()
|
||||
.map_or_else(|| (0, 0), |writer| (writer.width(), writer.height()))
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
pub mod ascii;
|
||||
pub mod colour;
|
||||
pub mod font;
|
||||
pub mod framebuffer;
|
||||
pub mod writer;
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
#![expect(dead_code)]
|
||||
use core::fmt;
|
||||
use spin::{Lazy, Mutex};
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
use super::{colour::Colour, font::Font, framebuffer::FRAMEBUFFER_WRITER};
|
||||
|
||||
static FONT_WIDTH: u32 = 8;
|
||||
static FONT_HEIGHT: u32 = 16;
|
||||
|
||||
pub static WRITER: Lazy<Mutex<Writer>> = Lazy::new(|| Mutex::new(Writer::new()));
|
||||
|
||||
pub fn screensize_chars() -> (u32, u32) {
|
||||
let writer = WRITER.lock();
|
||||
(writer.screen_width, writer.screen_height)
|
||||
}
|
||||
|
||||
pub struct Writer {
|
||||
font: &'static Font,
|
||||
/// Measured in chars not pixels.
|
||||
screen_width: u32,
|
||||
/// Measured in chars not pixels.
|
||||
screen_height: u32,
|
||||
/// 16 pixels tall.
|
||||
text_line: u32,
|
||||
/// 8 pixels wide.
|
||||
text_col: u32,
|
||||
|
||||
fg_color: Colour,
|
||||
bg_color: Colour,
|
||||
}
|
||||
|
||||
impl Default for Writer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
pub fn new() -> Self {
|
||||
FRAMEBUFFER_WRITER.lock().as_mut().map_or_else(
|
||||
|| {
|
||||
panic!("Framebuffer writer not initialized.");
|
||||
},
|
||||
|writer| Self {
|
||||
font: &crate::DEFAULT_FONT,
|
||||
screen_width: writer.width() / 8,
|
||||
screen_height: writer.height() / 16,
|
||||
text_line: 0,
|
||||
text_col: 0,
|
||||
fg_color: Colour::White,
|
||||
bg_color: Colour::Black,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub const fn set_font(&mut self, font: &'static Font) {
|
||||
self.font = font;
|
||||
}
|
||||
|
||||
/// This is sent when the user types a backspace.
|
||||
const BACKSPACE: u8 = 8;
|
||||
|
||||
pub fn write_glyph(&mut self, c: u8) {
|
||||
if c == b'\n' {
|
||||
self.newline();
|
||||
return;
|
||||
} else if c == Self::BACKSPACE {
|
||||
self.backspace();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the character data from the font array. -- each byte is a row of
|
||||
// pixels
|
||||
let data: &[u8] = self.font.glyph_for(c as u16);
|
||||
|
||||
if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() {
|
||||
for (row, line) in data.iter().enumerate().take(16) {
|
||||
for col in 0..8 {
|
||||
let pixel_x: u32 = self.text_col * FONT_WIDTH + col;
|
||||
let pixel_y: u32 = self.text_line * FONT_HEIGHT + row as u32;
|
||||
|
||||
if line & (0x80 >> col) != 0 {
|
||||
// Write the foreground color
|
||||
writer.write_pixel(
|
||||
pixel_x as usize,
|
||||
pixel_y as usize,
|
||||
self.fg_color,
|
||||
);
|
||||
} else {
|
||||
// Write the background color
|
||||
writer.write_pixel(
|
||||
pixel_x as usize,
|
||||
pixel_y as usize,
|
||||
self.bg_color,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go to next position
|
||||
if self.text_col + 1 >= self.screen_width {
|
||||
self.newline();
|
||||
} else {
|
||||
self.text_col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn dimensions(&self) -> (u32, u32) {
|
||||
(self.screen_width, self.screen_height)
|
||||
}
|
||||
|
||||
pub const fn next_char(&mut self) {
|
||||
self.text_col += 1;
|
||||
}
|
||||
|
||||
pub const fn newline(&mut self) {
|
||||
self.text_col = 0;
|
||||
|
||||
if self.text_line + 1 >= self.screen_height {
|
||||
self.text_line = 0;
|
||||
} else {
|
||||
self.text_line += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the backspace character. TODO: Implement VT-100 style terminal
|
||||
/// control codes alongside a shell. Not simple.
|
||||
pub fn backspace(&mut self) {
|
||||
if self.text_col > 0 {
|
||||
self.text_col -= 1;
|
||||
// Blank out the previous char.
|
||||
self.write_glyph(b' ');
|
||||
self.text_col -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_string(&mut self, s: &str) {
|
||||
for c in s.chars() {
|
||||
self.write_glyph(c as u8);
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn set_colour(&mut self, fg: Colour, bg: Colour) {
|
||||
self.fg_color = fg;
|
||||
self.bg_color = bg;
|
||||
}
|
||||
|
||||
pub const fn reset_colour(&mut self) {
|
||||
self.fg_color = Colour::White;
|
||||
self.bg_color = Colour::Black;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Write for Writer {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
self.write_string(s);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write(args: fmt::Arguments, fg: Colour, bg: Colour) {
|
||||
use core::fmt::Write;
|
||||
|
||||
interrupts::without_interrupts(|| {
|
||||
let mut writer = WRITER.lock();
|
||||
writer.set_colour(fg, bg);
|
||||
writer.write_fmt(args).unwrap();
|
||||
writer.reset_colour();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
write(args, Colour::White, Colour::Black);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _print_err(args: fmt::Arguments) {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
write(args, Colour::Red, Colour::Black);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _print_log(args: fmt::Arguments) {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
write(args, Colour::Yellow, Colour::Black);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn clear_screen() {
|
||||
interrupts::without_interrupts(|| {
|
||||
let mut writer = WRITER.lock();
|
||||
writer.text_line = 0;
|
||||
writer.text_col = 0;
|
||||
|
||||
if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() {
|
||||
writer.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn reset_cursor() {
|
||||
interrupts::without_interrupts(|| {
|
||||
let mut writer = WRITER.lock();
|
||||
writer.text_line = 0;
|
||||
writer.text_col = 0;
|
||||
});
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println_log {
|
||||
() => ($crate::print_log!("\n"));
|
||||
($($arg:tt)*) => ($crate::print_log!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print_log {
|
||||
($($arg:tt)*) => ($crate::_print_log(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
() => ($crate::print!("\n"));
|
||||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => ($crate::_print(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! printlnerr {
|
||||
() => ($crate::printerr!("\n"));
|
||||
($($arg:tt)*) => ($crate::printerr!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! printerr {
|
||||
($($arg:tt)*) => ($crate::_print_err(format_args!($($arg)*)));
|
||||
}
|
||||
Reference in New Issue
Block a user