Skip to content
Snippets Groups Projects
Commit 7f7968af authored by Eemeli Lehtonen's avatar Eemeli Lehtonen
Browse files

framebuffer logger + some ansi escapes

parent b21393cc
No related branches found
No related tags found
No related merge requests found
use crate::video::framebuffer::Color;
/// foreground color can be changed like this: "\x1B[38;2;<r>;<g>;<b>m"
/// background color can be changed like this: "\x1B[48;2;<r>;<g>;<b>m"
///
/// THESE ARE NON STANDARD ESCAPE SEQUENCES
pub struct EscapeDecoder {
buf: [u8; LONGEST_ESCAPE],
len: u8,
}
pub enum DecodedPart {
Byte(u8),
/// Null terminated
Bytes([u8; LONGEST_ESCAPE]),
FgColor(Color),
BgColor(Color),
Reset,
None,
}
//
impl EscapeDecoder {
pub const fn new() -> Self {
Self {
buf: [0; LONGEST_ESCAPE],
len: 0,
}
}
pub fn next(&mut self, byte: u8) -> DecodedPart {
match (self.len, byte) {
(0, b'\x1B') => {
self.len += 1;
self.buf[0 as usize] = byte;
DecodedPart::None
}
(0, _) => DecodedPart::Byte(byte),
(1, b'[') => {
self.len += 1;
self.buf[1 as usize] = byte;
DecodedPart::None
}
(i, b'm') => {
self.len += 1;
self.buf[i as usize] = byte;
// crate::qemu::_print(format_args_nl!(
// "seq part: {:?}",
// core::str::from_utf8(&self.buf[..self.len as usize])
// ));
let result = match self.buf[..self.len as usize] {
[b'\x1B', b'[', b'3', b'8', b';', b'2', b';', ref rgb @ .., b'm'] => {
Self::parse_rgb_part(rgb).map(DecodedPart::FgColor)
}
[b'\x1B', b'[', b'4', b'8', b';', b'2', b';', ref rgb @ .., b'm'] => {
Self::parse_rgb_part(rgb).map(DecodedPart::BgColor)
}
[b'\x1B', b'[', b'm'] => Some(DecodedPart::Reset),
_ => None,
};
if let Some(result) = result {
self.clear();
result
} else {
self.clear()
}
}
(i @ LONGEST_ESCAPE_PREV_U8.., _) => {
self.len += 1;
self.buf[i as usize] = byte;
self.clear()
}
(i, _) => {
self.len += 1;
self.buf[i as usize] = byte;
DecodedPart::None
}
}
}
pub fn clear(&mut self) -> DecodedPart {
self.len = 0;
DecodedPart::Bytes(core::mem::take(&mut self.buf))
}
fn parse_rgb_part(rgb: &[u8]) -> Option<Color> {
let mut iter = rgb.split(|c| *c == b';');
let r = core::str::from_utf8(iter.next()?).ok()?.parse().ok()?;
let g = core::str::from_utf8(iter.next()?).ok()?.parse().ok()?;
let b = core::str::from_utf8(iter.next()?).ok()?.parse().ok()?;
Some(Color::new(r, g, b))
}
}
//
// longest supported: "\x1B[48;2;255;255;255m"
const LONGEST_ESCAPE: usize = "\x1B[48;2;255;255;255m".len();
const LONGEST_ESCAPE_PREV: usize = LONGEST_ESCAPE - 1;
const LONGEST_ESCAPE_U8: u8 = LONGEST_ESCAPE as u8;
const LONGEST_ESCAPE_PREV_U8: u8 = LONGEST_ESCAPE as u8 - 1;
use core::fmt;
//
pub trait EscapeEncoder {
fn with_escape_code<'a>(&'a self, code: &'a str) -> EncodedPart<'a, Self> {
EncodedPart { code, data: self }
}
fn red(&self) -> EncodedPart<Self> {
self.with_escape_code("\x1B[38;2;255;0;0m")
}
fn green(&self) -> EncodedPart<Self> {
self.with_escape_code("\x1B[38;2;0;255;0m")
}
fn blue(&self) -> EncodedPart<Self> {
self.with_escape_code("\x1B[38;2;0;0;255m")
}
fn cyan(&self) -> EncodedPart<Self> {
self.with_escape_code("\x1B[38;2;0;255;255m")
}
fn magenta(&self) -> EncodedPart<Self> {
self.with_escape_code("\x1B[38;2;255;0;255m")
}
fn yellow(&self) -> EncodedPart<Self> {
self.with_escape_code("\x1B[38;2;255;255;0m")
}
}
pub struct EncodedPart<'a, T: ?Sized> {
code: &'a str,
data: &'a T,
}
//
impl EscapeEncoder for &str {}
impl<'a, T> fmt::Display for EncodedPart<'a, T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}{}\x1B[m", self.code, self.data)
}
}
impl<'a, T> fmt::Debug for EncodedPart<'a, T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.code)?;
self.data.fmt(f)?;
write!(f, "\x1B[m")
}
}
pub mod decode;
pub mod encode;
pub mod escape;
src/video/font.bmp

192 KiB

use crate::term::escape::decode::{DecodedPart, EscapeDecoder};
use super::{
font::FONT,
framebuffer::{get_fbo, Color, Framebuffer, FBO},
};
use core::fmt::{self, Arguments, Write};
use spin::{Lazy, Mutex, MutexGuard, Once};
//
pub fn _print(args: Arguments) {
_ = WRITER.lock().write_fmt(args)
}
//
static WRITER: Mutex<Writer> = Mutex::new(Writer::new());
//
struct Writer {
cursor: [u16; 2],
fg_color: Color,
bg_color: Color,
escapes: EscapeDecoder,
}
//
impl Writer {
pub fn write_bytes(&mut self, bytes: &[u8]) {
for byte in bytes {
self.write_byte(*byte)
}
}
pub fn write_byte(&mut self, byte: u8) {
match self.escapes.next(byte) {
DecodedPart::Byte(b'\n') => {
if let Some(mut fbo) = get_fbo() {
self.new_line(1, &mut fbo)
}
}
DecodedPart::Byte(b'\t') => {
self.cursor[0] = (self.cursor[0] / 4 + 1) * 4;
}
DecodedPart::Byte(byte) => self.write_byte_raw(byte),
DecodedPart::Bytes(bytes) => bytes
.into_iter()
.take_while(|b| *b != 0)
.for_each(|byte| self.write_byte_raw(byte)),
DecodedPart::FgColor(color) => self.fg_color = color,
DecodedPart::BgColor(color) => self.bg_color = color,
DecodedPart::Reset => {
self.fg_color = Self::FG_COLOR;
self.bg_color = Self::BG_COLOR;
}
DecodedPart::None => {}
}
}
pub fn write_byte_raw(&mut self, byte: u8) {
if let Some(mut fbo) = get_fbo() {
let size = Self::size(&mut fbo);
if size[0] == 0 || size[1] == 0 {
return;
}
self._write_byte_raw(byte, &mut fbo);
}
}
const FG_COLOR: Color = Color::from_hex("#bbbbbb");
const BG_COLOR: Color = Color::from_hex("#000000");
const fn new() -> Self {
Self {
cursor: [0; 2],
fg_color: Self::FG_COLOR,
bg_color: Self::BG_COLOR,
escapes: EscapeDecoder::new(),
}
}
fn _write_byte_raw(&mut self, byte: u8, fbo: &mut MutexGuard<Framebuffer>) {
let (map, is_double) = FONT[byte as usize];
// insert a new line if the next character would be off screen
if self.cursor[0] + if is_double { 1 } else { 0 } >= Self::size(fbo)[0] {
self.new_line(8, fbo);
}
let (x, y) = (self.cursor[0] as usize * 8, self.cursor[1] as usize * 16);
self.cursor[0] += if is_double { 2 } else { 1 };
for (yd, row) in map.into_iter().enumerate() {
for xd in 0..if is_double { 16 } else { 8 } {
fbo.set(
x + xd,
y + yd,
if (row & 1 << xd) != 0 {
self.fg_color
} else {
self.bg_color
},
);
}
}
}
fn new_line(&mut self, count: u16, fbo: &mut MutexGuard<Framebuffer>) {
self.cursor[0] = 0;
self.cursor[1] += 1;
if self.cursor[1] >= Self::size(fbo)[1] {
let scroll_count = count.min(self.cursor[1]);
self.cursor[1] -= scroll_count;
fbo.scroll(16 * scroll_count as usize);
}
}
fn size(fbo: &mut MutexGuard<Framebuffer>) -> [u16; 2] {
[(fbo.width / 16) as _, (fbo.height / 16) as _]
}
}
impl fmt::Write for Writer {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write_bytes(s.as_bytes());
Ok(())
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment