diff --git a/include/kernel/clock/time.h b/include/kernel/clock/time.h new file mode 100644 index 0000000..b6cb4de --- /dev/null +++ b/include/kernel/clock/time.h @@ -0,0 +1,15 @@ +#ifndef TIME_H +#define TIME_H + +#include + +// 使用UNIX时间戳 +usize system_time_get(); + +// 如果硬件支持更高的计时精度, +// 此函数提供从系统unix时间开始到现在的纳秒为单位的时间 +usize system_time_ns_get(); + +void system_time_increase(); + +#endif diff --git a/include/kernel/tty.h b/include/kernel/tty.h index 1a8395d..2a1e6c3 100644 --- a/include/kernel/tty.h +++ b/include/kernel/tty.h @@ -6,7 +6,7 @@ typedef enum __tty_type { - invalid = 0, + tty_type_invalid = 0, // 用于在内核刚刚被引导,只有bootloader提供的显示功能时使用 tty_type_raw_framebuffer = 1, // 用于图形功能初始化后,直接连接图形接口 @@ -40,8 +40,9 @@ typedef struct __framebuffer framebuffer; // 文本模式中的字符由tty模块渲染 typedef enum __tty_mode { - tty_mode_text = 0, - tty_mode_graphics = 1, + tty_mode_invalid = 0, + tty_mode_text = 1, + tty_mode_graphics = 2, } tty_mode; typedef struct __tty_text_state @@ -55,6 +56,7 @@ typedef struct __tty_text_state typedef struct __tty { usize id; + usize width, height; tty_type type; tty_typeinfo typeinfo; tty_mode mode; @@ -120,6 +122,14 @@ void tty_text_print(tty *ttyx, char *string, u32 color, u32 bgcolor); #define gen_color(r, g, b) (((r) << 16) | ((g) << 8) | (b)) +usize tty_get_width(tty *ttyx); +usize tty_get_height(tty *ttyx); + +tty_type tty_get_type(tty *ttyx); +tty_mode tty_get_mode(tty *ttyx); + +bool tty_is_enabled(tty *ttyx); + /** * @brief 打开某个tty * @@ -130,7 +140,6 @@ void tty_text_print(tty *ttyx, char *string, u32 color, u32 bgcolor); * 类型的tty占用 */ bool tty_enable(tty *ttyx); - void tty_disable(tty *ttyx); #define TTY_FONT_SCALE 2 diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 8a1f78a..093fa03 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -11,7 +11,7 @@ ifdef release CCFLAGS := ${CCFLAGS} -O2 endif -C_SRCS = main.c tty.c font.c memm.c memm_${ARCH}.c raw.c +C_SRCS = main.c tty.c font.c memm.c memm_${ARCH}.c raw.c time.c C_OBJS = ${C_SRCS:.c=.c.o} ################################ @@ -38,7 +38,7 @@ STRIP_SECS = -R .note.GNU-stack OBJCOPY_FLAGS = ${STRIP_SECS} # 子目录 -VPATH = memm/ memm/allocator tty/ klog/ arch/${ARCH} +VPATH = memm/ memm/allocator tty/ klog/ arch/${ARCH} clock/ %.c.o: %.c @echo -e "\e[1m\e[33m${CC}\e[0m \e[32m$<\e[0m \e[34m-->\e[0m \e[1m\e[32m$@\e[0m" diff --git a/src/kernel/clock/mod.rs b/src/kernel/clock/mod.rs new file mode 100644 index 0000000..077885d --- /dev/null +++ b/src/kernel/clock/mod.rs @@ -0,0 +1 @@ +pub mod time; diff --git a/src/kernel/clock/time.c b/src/kernel/clock/time.c new file mode 100644 index 0000000..c9af49b --- /dev/null +++ b/src/kernel/clock/time.c @@ -0,0 +1,20 @@ +#include +#include + +usize system_time; +usize system_time_ns; + +usize system_time_get() +{ + return system_time; +} + +usize system_time_ns_get() +{ + return system_time_ns; +} + +void system_time_increase() +{ + system_time++; +} diff --git a/src/kernel/clock/time.rs b/src/kernel/clock/time.rs new file mode 100644 index 0000000..b0b0e66 --- /dev/null +++ b/src/kernel/clock/time.rs @@ -0,0 +1,165 @@ +use std::{cmp::Ordering, fmt::Debug, ops::Sub, time::Duration}; + +extern "C" { + fn system_time_get() -> usize; + fn system_time_ns_get() -> usize; +} + +#[derive(Debug)] +pub struct SystemTimeError(Duration); + +#[derive(Clone, Copy, Hash)] +pub struct SystemTime { + unix_time: usize, + ns_time: usize, +} + +impl Debug for SystemTime { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let second_dur = 1000usize; + let minute_dur = second_dur * 60; + let hour_dur = minute_dur * 60; + let day_dur = hour_dur * 24; + let year_dur = day_dur * 365; + let four_year_dur = day_dur * (365 * 4 + 1); + + let year = 1970 + + self.unix_time / four_year_dur * 4 + + if self.unix_time % four_year_dur < day_dur * 59 { + 0 + } else { + (self.unix_time % four_year_dur - day_dur) / year_dur + }; + let rest = self.unix_time % four_year_dur; + let mut leap = false; + let rest = if rest < day_dur * 59 { + rest + } else { + if rest < 60 { + leap = true; + } + rest - day_dur + }; + let month = rest % year_dur; + let mut day = 0; + let month = if month < 31 * day_dur { + day = month; + 1 + } else if month < (31 + 28) * day_dur { + day = month - 31 * day_dur; + 2 + } else if month < (31 + 28 + 31) * day_dur { + day = month - (31 + 28) * day_dur; + 3 + } else if month < (31 + 28 + 31 + 30) * day_dur { + day = month - (31 + 28 + 31) * day_dur; + 4 + } else if month < (31 + 28 + 31 + 30 + 31) * day_dur { + day = month - (31 + 28 + 31 + 30) * day_dur; + 5 + } else if month < (31 + 28 + 31 + 30 + 31 + 30) * day_dur { + day = month - (31 + 28 + 31 + 30 + 31) * day_dur; + 6 + } else if month < (31 + 28 + 31 + 30 + 31 + 30 + 31) * day_dur { + day = month - (31 + 28 + 31 + 30 + 31 + 30) * day_dur; + 7 + } else if month < (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31) * day_dur { + day = month - (31 + 28 + 31 + 30 + 31 + 30 + 31) * day_dur; + 8 + } else if month < (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30) * day_dur { + day = month - (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31) * day_dur; + 9 + } else if month < (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31) * day_dur { + day = month - (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30) * day_dur; + 10 + } else if month < (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) * day_dur { + day = month - (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31) * day_dur; + 11 + } else if month < (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31) * day_dur { + day = month - (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) * day_dur; + 12 + } else { + 0 + }; + let mut hour = day % day_dur; + day /= day_dur; + day += 1; + if leap { + day += 1; + } + let mut minute = hour % hour_dur; + hour /= hour_dur; + let mut second = minute % minute_dur; + minute /= minute_dur; + let milisec = second % second_dur; + second /= second_dur; + write!( + f, + "[{:02}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}]", + year, month, day, hour, minute, second, milisec + ) + } +} + +impl Eq for SystemTime {} +impl PartialEq for SystemTime { + fn eq(&self, other: &Self) -> bool { + self.unix_time == other.unix_time && self.ns_time == other.ns_time + } +} + +impl Ord for SystemTime { + fn cmp(&self, other: &Self) -> Ordering { + match self.unix_time.cmp(&other.unix_time) { + Ordering::Equal => self.ns_time.cmp(&other.ns_time), + ord => ord, + } + } +} + +impl PartialOrd for SystemTime { + fn partial_cmp(&self, other: &Self) -> Option { + match self.unix_time.partial_cmp(&other.unix_time) { + Some(Ordering::Equal) => self.ns_time.partial_cmp(&other.ns_time), + ord => ord, + } + } +} + +impl Sub for SystemTime { + type Output = Result; + + fn sub(self, rhs: SystemTime) -> Self::Output { + if self < rhs { + let earl = (rhs - self).unwrap(); + Err(SystemTimeError(earl)) + } else { + let usdiff = self.ns_time as isize - self.ns_time as isize; + let usdiff = if usdiff >= 0 { + Duration::from_nanos(usdiff as usize as u64) + } else { + Duration::from_nanos(0) - Duration::from_nanos((-usdiff) as usize as u64) + }; + Ok(Duration::from_millis((self.unix_time - rhs.unix_time) as u64) + usdiff) + } + } +} + +impl SystemTime { + pub fn now() -> Self { + unsafe { + Self { + unix_time: system_time_get(), + ns_time: system_time_ns_get(), + } + } + } + + pub fn duration_since(&self, earlier: &SystemTime) -> Result { + *self - *earlier + } + + pub fn elapsed(&self) -> Result { + SystemTime::now() - *self + } +} diff --git a/src/kernel/klog.rs b/src/kernel/klog.rs new file mode 100644 index 0000000..41e4f23 --- /dev/null +++ b/src/kernel/klog.rs @@ -0,0 +1,160 @@ +use super::{ + clock::time::SystemTime, + tty::tty::{Color, Message, MessageBuilder}, +}; + +#[derive(PartialEq)] +pub enum LoggerLevel { + Fatal, + Error, + Warning, + Info, + Debug, + Trace, +} + +pub struct KernelLogger { + fatal_queue: Vec<(SystemTime, Message)>, + error_queue: Vec<(SystemTime, Message)>, + warning_queue: Vec<(SystemTime, Message)>, + info_queue: Vec<(SystemTime, Message)>, + debug_queue: Vec<(SystemTime, Message)>, + trace_queue: Vec<(SystemTime, Message)>, +} + +impl KernelLogger { + pub fn new() -> Self { + Self { + fatal_queue: vec![], + error_queue: vec![], + warning_queue: vec![], + info_queue: vec![], + debug_queue: vec![], + trace_queue: vec![], + } + } + + pub fn fatal(&mut self, msg: Message) { + let msg = MessageBuilder::new() + .message("Fatal: ".to_string()) + .foreground_color(Color(0xee, 0xa, 0xa)) + .append(MessageBuilder::from_message(&msg)) + .build(); + self.fatal_queue.push((SystemTime::now(), msg)); + } + + pub fn error(&mut self, msg: Message) { + let msg = MessageBuilder::new() + .message("Error: ".to_string()) + .foreground_color(Color(0xaa, 0x22, 0x22)) + .append(MessageBuilder::from_message(&msg)) + .build(); + self.error_queue.push((SystemTime::now(), msg)); + } + + pub fn warning(&mut self, msg: Message) { + let msg = MessageBuilder::new() + .message("Warning: ".to_string()) + .foreground_color(Color(0xaa, 0xa, 0xaa)) + .append(MessageBuilder::from_message(&msg)) + .build(); + self.warning_queue.push((SystemTime::now(), msg)); + } + + pub fn info(&mut self, msg: Message) { + let msg = MessageBuilder::new() + .message("Info: ".to_string()) + .foreground_color(Color(0xa, 0xee, 0xa)) + .append(MessageBuilder::from_message(&msg)) + .build(); + self.info_queue.push((SystemTime::now(), msg)); + } + + pub fn debug(&mut self, msg: Message) { + let msg = MessageBuilder::new() + .message("Debug: ".to_string()) + .foreground_color(Color(0xee, 0xee, 0xee)) + .append(MessageBuilder::from_message(&msg)) + .build(); + self.debug_queue.push((SystemTime::now(), msg)); + } + + pub fn trace(&mut self, msg: Message) { + let msg = MessageBuilder::new() + .message("Trace: ".to_string()) + .foreground_color(Color(0xee, 0xee, 0xee)) + .append(MessageBuilder::from_message(&msg)) + .build(); + self.trace_queue.push((SystemTime::now(), msg)); + } + + pub fn iter(&self, level: LoggerLevel) -> LogIterator { + let mut logs = vec![]; + if level == LoggerLevel::Fatal { + logs.push(&self.fatal_queue); + } + if level == LoggerLevel::Fatal || level == LoggerLevel::Error { + logs.push(&self.error_queue); + } + if level == LoggerLevel::Fatal + || level == LoggerLevel::Error + || level == LoggerLevel::Warning + { + logs.push(&self.warning_queue); + } + if level == LoggerLevel::Fatal + || level == LoggerLevel::Error + || level == LoggerLevel::Warning + || level == LoggerLevel::Info + { + logs.push(&self.info_queue); + } + if level == LoggerLevel::Fatal + || level == LoggerLevel::Error + || level == LoggerLevel::Warning + || level == LoggerLevel::Info + || level == LoggerLevel::Debug + { + logs.push(&self.debug_queue); + } + if level == LoggerLevel::Fatal + || level == LoggerLevel::Error + || level == LoggerLevel::Warning + || level == LoggerLevel::Info + || level == LoggerLevel::Debug + || level == LoggerLevel::Trace + { + logs.push(&self.trace_queue); + } + let mut res = vec![]; + while let Some(msg) = { + logs.iter_mut() + .filter_map(|&mut l| l.first().cloned()) + .min_by_key(|&(syst, _)| syst) + } { + res.push(msg); + } + LogIterator { logs: res } + } +} + +pub struct LogIterator { + logs: Vec<(SystemTime, Message)>, +} + +impl Iterator for LogIterator { + type Item = Message; + + fn next(&mut self) -> Option { + if let Some((time, msg)) = self.logs.first() { + Some( + MessageBuilder::new() + .message(format!("{:?}", time)) + .append(MessageBuilder::from_message(msg)) + .build(), + ) + } else { + None + } + } +} diff --git a/src/kernel/klog/klog.rs b/src/kernel/klog/klog.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/kernel/main.rs b/src/kernel/main.rs index cf8c6e4..5d0373a 100644 --- a/src/kernel/main.rs +++ b/src/kernel/main.rs @@ -1,15 +1,19 @@ -use crate::kernel::tty::tty::{Color, MessageBuilder, Tty}; +use super::{ + klog::{KernelLogger, LoggerLevel}, + tty::tty::{Color, ColorPair, Message, Tty}, +}; #[no_mangle] extern "C" fn kmain_rust() { + let mut logger = KernelLogger::new(); + logger.info(Message::from(format!( + "Hello, {:?}Metaverse{:?}!", + ColorPair::color(Color(0xa, 0xee, 0xa), Color(0, 0, 0)), + ColorPair::Reset + ))); let tty = Tty::from_id(0).unwrap(); - tty.enable(); - let hello = MessageBuilder::new() - .message("Hello, ".to_string()) - .message("Metaverse".to_string()) - .foreground_color(Color(0xa, 0xee, 0xa)) - .message("!\n".to_string()) - .build(); - tty.print(hello); + for msg in logger.iter(LoggerLevel::Info) { + tty.print(msg); + } loop {} } diff --git a/src/kernel/memm/memm.rs b/src/kernel/memm/memm.rs index fc41bf3..3995400 100644 --- a/src/kernel/memm/memm.rs +++ b/src/kernel/memm/memm.rs @@ -4,7 +4,7 @@ use core::alloc::{GlobalAlloc, Layout}; extern "C" { pub fn memm_kernel_allocate(size: usize) -> *mut u8; - pub fn memm_user_allocate(size: usize, pid: usize); + // pub fn memm_user_allocate(size: usize, pid: usize); pub fn memm_free(mem: *mut u8); } diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 14f7bad..583319c 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,3 +1,6 @@ +pub mod clock; +pub mod klog; +pub mod main; pub mod memm; pub mod tty; -pub mod main; +pub mod sync; diff --git a/src/kernel/sync/mod.rs b/src/kernel/sync/mod.rs new file mode 100644 index 0000000..2ba968f --- /dev/null +++ b/src/kernel/sync/mod.rs @@ -0,0 +1 @@ +pub mod rwlock; diff --git a/src/kernel/sync/rwlock.rs b/src/kernel/sync/rwlock.rs new file mode 100644 index 0000000..be7a430 --- /dev/null +++ b/src/kernel/sync/rwlock.rs @@ -0,0 +1,130 @@ +use std::{ + ops::{Deref, DerefMut}, + ptr::null_mut, +}; + +/// ## RwLock +/// 读写锁 +/// +/// * 对于写入操作: +/// +/// 锁没有占用时,获取锁,并执行闭包。 +/// +/// 当锁已经被占用,将闭包悬挂。 +/// +/// 释放锁时,将所有悬挂的闭包都执行。 +/// +/// 正在释放锁时,`write`方法返回`Err(())` +/// +/// ``` +/// let num = 6; +/// let num = RwLock::new(num); +/// if let Err(()) = num.write( +/// |n| *n = 10 +/// ) {} +/// let numstr = format!("{}", num.read()); +/// ```` +pub struct RwLock<'a, T> { + obj: T, + locked: bool, + dealing_hanged: bool, + ptr: *mut RwLockWriteGuard<'a, T>, + hanging: Vec<&'a dyn Fn(&mut T)>, +} + +unsafe impl Send for RwLock<'_, T> {} +unsafe impl Sync for RwLock<'_, T> {} + +impl<'a, T> RwLock<'a, T> { + pub fn new(obj: T) -> Self { + Self { + obj, + locked: false, + dealing_hanged: false, + ptr: null_mut(), + hanging: vec![], + } + } + + pub fn read(&self) -> RwLockReadGuard { + RwLockReadGuard { obj: &self.obj } + } + + pub fn write(&'a mut self, f: &'a dyn Fn(&mut T)) -> Result, ()> { + if self.dealing_hanged { + Err(()) + } else if !self.locked { + self.locked = true; + f(&mut self.obj); + let ptr = { self as *mut RwLock<'a, T> }; + let obj = &mut self.obj; + let mut res = RwLockWriteGuard { + obj, + ptr, + must_deal_hang: false, + }; + self.ptr = &mut res as *mut RwLockWriteGuard<'_, T>; + Ok(res) + } else { + self.hanging.push(f); + let ptr = { self as *mut RwLock<'a, T> }; + let obj = &mut self.obj; + Ok(RwLockWriteGuard { + obj, + ptr, + must_deal_hang: false, + }) + } + } +} + +pub struct RwLockReadGuard<'a, T> { + obj: &'a T, +} + +impl<'a, T> Deref for RwLockReadGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.obj + } +} + +impl<'a, T> Drop for RwLockReadGuard<'a, T> { + fn drop(&mut self) {} +} + +pub struct RwLockWriteGuard<'a, T> { + obj: &'a mut T, + ptr: *mut RwLock<'a, T>, + must_deal_hang: bool, +} + +impl<'a, T> Deref for RwLockWriteGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.obj + } +} + +impl<'a, T> DerefMut for RwLockWriteGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.obj + } +} + +impl<'a, T> Drop for RwLockWriteGuard<'a, T> { + fn drop(&mut self) { + if self.must_deal_hang { + let p = unsafe { &mut *self.ptr }; + p.dealing_hanged = true; + for f in p.hanging.iter() { + f(self.obj); + } + p.hanging.clear(); + p.dealing_hanged = false; + p.locked = false; + } + } +} diff --git a/src/kernel/tty/tty.c b/src/kernel/tty/tty.c index a2af9b2..809445c 100644 --- a/src/kernel/tty/tty.c +++ b/src/kernel/tty/tty.c @@ -32,6 +32,8 @@ tty *tty_new(tty_type type, tty_mode mode) res->type = type; res->mode = mode; res->enabled = false; + res->width = 0; + res->height = 0; return res; } @@ -52,6 +54,8 @@ void tty_set_framebuffer(tty *ttyx, framebuffer *fb) if (ttyx->type != tty_type_raw_framebuffer) return; memcpy(&ttyx->typeinfo.raw_framebuffer, fb, sizeof(framebuffer)); + ttyx->width = ttyx->typeinfo.raw_framebuffer.width; + ttyx->height = ttyx->typeinfo.raw_framebuffer.height; if (ttyx->mode == tty_mode_text) { ttyx->text.width = fb->width / tty_get_font()->char_width; @@ -140,6 +144,9 @@ void tty_text_print(tty *ttyx, char *string, u32 color, u32 bgcolor) { if (ttyx->enabled == false) return; + // TODO 暂时只支持framebuffer + if (ttyx->type != tty_type_raw_framebuffer) + return; if (ttyx->mode != tty_mode_text) return; if (ttyx->typeinfo.raw_framebuffer.pixtype == bgr) @@ -224,6 +231,35 @@ void tty_text_print(tty *ttyx, char *string, u32 color, u32 bgcolor) simple_lock_unlock(ttyx->text.lock); } +usize tty_get_width(tty *ttyx) +{ + if (ttyx->mode == tty_mode_text) + return ttyx->text.width; + return ttyx->width; +} + +usize tty_get_height(tty *ttyx) +{ + if (ttyx->mode == tty_mode_text) + return ttyx->text.height; + return ttyx->height; +} + +tty_type tty_get_type(tty *ttyx) +{ + return ttyx->type; +} + +tty_mode tty_get_mode(tty *ttyx) +{ + return ttyx->mode; +} + +bool tty_is_enabled(tty *ttyx) +{ + return ttyx->enabled; +} + bool tty_enable(tty *ttyx) { if (tty_ctrler.enabled[ttyx->id]) diff --git a/src/kernel/tty/tty.rs b/src/kernel/tty/tty.rs index 1f33a1a..9ab4c65 100644 --- a/src/kernel/tty/tty.rs +++ b/src/kernel/tty/tty.rs @@ -1,11 +1,19 @@ -use std::ptr::null_mut; +use std::{fmt::Debug, ptr::null_mut}; extern "C" { fn tty_new(tty_type: u8, mode: u8) -> *mut u8; fn tty_get(id: usize) -> *mut *mut u8; - pub fn tty_text_print(ttyx: *mut u8, string: *mut u8, color: u32, bgcolor: u32); + fn tty_text_print(ttyx: *mut u8, string: *mut u8, color: u32, bgcolor: u32); fn tty_get_id(tty: *mut u8) -> usize; + fn tty_get_width(tty: *mut u8) -> usize; + fn tty_get_height(tty: *mut u8) -> usize; + + fn tty_get_type(tty: *mut u8) -> u8; + fn tty_get_mode(tty: *mut u8) -> u8; + + fn tty_is_enabled(tty: *mut u8) -> bool; + fn tty_enable(tty: *mut u8) -> bool; fn tty_disable(tty: *mut u8); } @@ -17,9 +25,31 @@ pub enum Type { VirtualTerm = 3, } +impl From for Type { + fn from(value: u8) -> Self { + match value { + 1 => Type::RawFramebuffer, + 2 => Type::Display, + 3 => Type::VirtualTerm, + _ => Type::Invalid, + } + } +} + pub enum Mode { - Text = 0, - Graphics = 1, + Invalid = 0, + Text = 1, + Graphics = 2, +} + +impl From for Mode { + fn from(value: u8) -> Self { + match value { + 1 => Mode::Text, + 2 => Mode::Graphics, + _ => Mode::Invalid, + } + } } pub struct Tty { @@ -50,6 +80,29 @@ impl Tty { unsafe { tty_get_id(self.tty_pointer) } } + pub fn size(&self) -> Resolution { + unsafe { + Resolution { + width: tty_get_width(self.tty_pointer), + height: tty_get_height(self.tty_pointer), + } + } + } + + pub fn get_type(&self) -> Type { + let tp = unsafe { tty_get_type(self.tty_pointer) }; + Type::from(tp) + } + + pub fn mode(&self) -> Mode { + let mode = unsafe { tty_get_mode(self.tty_pointer) }; + Mode::from(mode) + } + + pub fn is_enabled(&self) -> bool { + unsafe { tty_is_enabled(self.tty_pointer) } + } + pub fn enable(&self) { unsafe { tty_enable(self.tty_pointer) }; } @@ -82,8 +135,45 @@ impl Tty { } } +#[derive(Clone, Copy)] pub struct Color(pub u8, pub u8, pub u8); +impl ToString for Color { + fn to_string(&self) -> String { + format!("Color({:02x}, {:02x}, {:02x})", self.0, self.1, self.2) + } +} + +impl Debug for Color { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:02x}{:02x}{:02x}", self.0, self.1, self.2) + } +} + +pub enum ColorPair { + Reset, + Color { fore: Color, back: Color }, +} + +impl ColorPair { + pub fn reset() -> Self { + ColorPair::Reset + } + + pub fn color(fore: Color, back: Color) -> Self { + ColorPair::Color { fore, back } + } +} + +impl Debug for ColorPair { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ColorPair::Reset => write!(f, "\x1b{{}}"), + ColorPair::Color { fore, back } => write!(f, "\x1b{{{:?}{:?}}}", fore, back), + } + } +} + impl From for u32 { fn from(value: Color) -> Self { let res = (value.0 as u32) << 16 | (value.1 as u32) << 8 | (value.2 as u32); @@ -91,14 +181,79 @@ impl From for u32 { } } +pub struct Resolution { + pub width: usize, + pub height: usize, +} + +#[derive(Clone)] pub struct MessageSection { msg: String, fgcolor: Color, bgcolor: Color, } +#[derive(Clone)] pub struct Message(Vec); +impl From for Message { + fn from(value: String) -> Self { + let mut res = MessageBuilder::new(); + let mut msg = String::new(); + let mut color = ColorPair::Reset; + let mut coloring = false; + + let mut colorp_str = String::new(); + + for c in value.as_bytes() { + if *c as char == '\x1b' { + coloring = true; + res.message_mut(msg.clone()); + msg.clear(); + if let ColorPair::Color { fore, back } = color { + res.foreground_color_mut(fore); + res.background_color_mut(back); + } + continue; + } + if coloring { + if *c as char == '{' { + colorp_str.clear(); + } else if *c as char == '}' { + if colorp_str.is_empty() { + color = ColorPair::Reset; + } else { + let bts = colorp_str.as_bytes(); + let r = bts[0] << 4 + bts[1]; + let g = bts[2] << 4 + bts[3]; + let b = bts[4] << 4 + bts[5]; + let fore = Color(r, g, b); + let r = bts[6] << 4 + bts[7]; + let g = bts[8] << 4 + bts[9]; + let b = bts[10] << 4 + bts[11]; + let back = Color(r, g, b); + color = ColorPair::Color { fore, back }; + } + coloring = false; + } else { + colorp_str.push(*c as char); + } + continue; + } + msg.push(*c as char); + } + if !msg.is_empty() { + res.message_mut(msg.clone()); + msg.clear(); + if let ColorPair::Color { fore, back } = color { + res.foreground_color_mut(fore); + res.background_color_mut(back); + } + } + res.build() + } +} + pub struct MessageBuilder { msg: Message, } @@ -110,6 +265,10 @@ impl MessageBuilder { } } + pub fn from_message(msg: &Message) -> Self { + Self { msg: msg.clone() } + } + pub fn message(mut self, msg: String) -> Self { self.msg.0.push(MessageSection { msg, @@ -119,6 +278,14 @@ impl MessageBuilder { self } + pub fn message_mut(&mut self, msg: String) { + self.msg.0.push(MessageSection { + msg, + fgcolor: Color(0xee, 0xee, 0xee), + bgcolor: Color(0, 0, 0), + }); + } + pub fn background_color(mut self, color: Color) -> Self { if let Some(msg) = self.msg.0.last_mut() { msg.bgcolor = color; @@ -126,6 +293,12 @@ impl MessageBuilder { self } + pub fn background_color_mut(&mut self, color: Color) { + if let Some(msg) = self.msg.0.last_mut() { + msg.bgcolor = color; + } + } + pub fn foreground_color(mut self, color: Color) -> Self { if let Some(msg) = self.msg.0.last_mut() { msg.fgcolor = color; @@ -133,6 +306,17 @@ impl MessageBuilder { self } + pub fn foreground_color_mut(&mut self, color: Color) { + if let Some(msg) = self.msg.0.last_mut() { + msg.fgcolor = color; + } + } + + pub fn append(mut self, mut builder: Self) -> Self { + self.msg.0.append(&mut builder.msg.0); + self + } + pub fn build(self) -> Message { self.msg }