增加内核日志功能 #3

Merged
pointer-to-bios merged 17 commits from pointer-to-bios/metaverse-dev:main into main 2024-02-05 22:10:26 +08:00
15 changed files with 749 additions and 21 deletions
Showing only changes of commit bfd7530ae2 - Show all commits

View File

@ -0,0 +1,15 @@
#ifndef TIME_H
#define TIME_H
#include <types.h>
// 使用UNIX时间戳
usize system_time_get();
// 如果硬件支持更高的计时精度,
// 此函数提供从系统unix时间开始到现在的纳秒为单位的时间
usize system_time_ns_get();
void system_time_increase();
#endif

View File

@ -6,7 +6,7 @@
typedef enum __tty_type typedef enum __tty_type
{ {
invalid = 0, tty_type_invalid = 0,
// 用于在内核刚刚被引导只有bootloader提供的显示功能时使用 // 用于在内核刚刚被引导只有bootloader提供的显示功能时使用
tty_type_raw_framebuffer = 1, tty_type_raw_framebuffer = 1,
// 用于图形功能初始化后,直接连接图形接口 // 用于图形功能初始化后,直接连接图形接口
@ -40,8 +40,9 @@ typedef struct __framebuffer framebuffer;
// 文本模式中的字符由tty模块渲染 // 文本模式中的字符由tty模块渲染
typedef enum __tty_mode typedef enum __tty_mode
{ {
tty_mode_text = 0, tty_mode_invalid = 0,
tty_mode_graphics = 1, tty_mode_text = 1,
tty_mode_graphics = 2,
} tty_mode; } tty_mode;
typedef struct __tty_text_state typedef struct __tty_text_state
@ -55,6 +56,7 @@ typedef struct __tty_text_state
typedef struct __tty typedef struct __tty
{ {
usize id; usize id;
usize width, height;
tty_type type; tty_type type;
tty_typeinfo typeinfo; tty_typeinfo typeinfo;
tty_mode mode; 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)) #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 * @brief tty
* *
@ -130,7 +140,6 @@ void tty_text_print(tty *ttyx, char *string, u32 color, u32 bgcolor);
* tty占用 * tty占用
*/ */
bool tty_enable(tty *ttyx); bool tty_enable(tty *ttyx);
void tty_disable(tty *ttyx); void tty_disable(tty *ttyx);
#define TTY_FONT_SCALE 2 #define TTY_FONT_SCALE 2

View File

@ -11,7 +11,7 @@ ifdef release
CCFLAGS := ${CCFLAGS} -O2 CCFLAGS := ${CCFLAGS} -O2
endif 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} C_OBJS = ${C_SRCS:.c=.c.o}
################################ ################################
@ -38,7 +38,7 @@ STRIP_SECS = -R .note.GNU-stack
OBJCOPY_FLAGS = ${STRIP_SECS} OBJCOPY_FLAGS = ${STRIP_SECS}
# 子目录 # 子目录
VPATH = memm/ memm/allocator tty/ klog/ arch/${ARCH} VPATH = memm/ memm/allocator tty/ klog/ arch/${ARCH} clock/
%.c.o: %.c %.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" @echo -e "\e[1m\e[33m${CC}\e[0m \e[32m$<\e[0m \e[34m-->\e[0m \e[1m\e[32m$@\e[0m"

1
src/kernel/clock/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod time;

20
src/kernel/clock/time.c Normal file
View File

@ -0,0 +1,20 @@
#include <kernel/clock/time.h>
#include <types.h>
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++;
}

165
src/kernel/clock/time.rs Normal file
View File

@ -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<std::cmp::Ordering> {
match self.unix_time.partial_cmp(&other.unix_time) {
Some(Ordering::Equal) => self.ns_time.partial_cmp(&other.ns_time),
ord => ord,
}
}
}
impl Sub<SystemTime> for SystemTime {
type Output = Result<Duration, SystemTimeError>;
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<Duration, SystemTimeError> {
*self - *earlier
}
pub fn elapsed(&self) -> Result<Duration, SystemTimeError> {
SystemTime::now() - *self
}
}

160
src/kernel/klog.rs Normal file
View File

@ -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<Self::Item> {
if let Some((time, msg)) = self.logs.first() {
Some(
MessageBuilder::new()
.message(format!("{:?}", time))
.append(MessageBuilder::from_message(msg))
.build(),
)
} else {
None
}
}
}

View File

@ -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] #[no_mangle]
extern "C" fn kmain_rust() { 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(); let tty = Tty::from_id(0).unwrap();
tty.enable(); for msg in logger.iter(LoggerLevel::Info) {
let hello = MessageBuilder::new() tty.print(msg);
.message("Hello, ".to_string()) }
.message("Metaverse".to_string())
.foreground_color(Color(0xa, 0xee, 0xa))
.message("!\n".to_string())
.build();
tty.print(hello);
loop {} loop {}
} }

View File

@ -4,7 +4,7 @@ use core::alloc::{GlobalAlloc, Layout};
extern "C" { extern "C" {
pub fn memm_kernel_allocate(size: usize) -> *mut u8; 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); pub fn memm_free(mem: *mut u8);
} }

View File

@ -1,3 +1,6 @@
pub mod clock;
pub mod klog;
pub mod main;
pub mod memm; pub mod memm;
pub mod tty; pub mod tty;
pub mod main; pub mod sync;

1
src/kernel/sync/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod rwlock;

130
src/kernel/sync/rwlock.rs Normal file
View File

@ -0,0 +1,130 @@
use std::{
ops::{Deref, DerefMut},
ptr::null_mut,
};
/// ## RwLock<T>
/// 读写锁
///
/// * 对于写入操作:
///
/// 锁没有占用时,获取锁,并执行闭包。
///
/// 当锁已经被占用,将闭包悬挂。
///
/// 释放锁时,将所有悬挂的闭包都执行。
///
/// 正在释放锁时,`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<T> Send for RwLock<'_, T> {}
unsafe impl<T> 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<T> {
RwLockReadGuard { obj: &self.obj }
}
pub fn write(&'a mut self, f: &'a dyn Fn(&mut T)) -> Result<RwLockWriteGuard<T>, ()> {
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;
}
}
}

View File

@ -32,6 +32,8 @@ tty *tty_new(tty_type type, tty_mode mode)
res->type = type; res->type = type;
res->mode = mode; res->mode = mode;
res->enabled = false; res->enabled = false;
res->width = 0;
res->height = 0;
return res; return res;
} }
@ -52,6 +54,8 @@ void tty_set_framebuffer(tty *ttyx, framebuffer *fb)
if (ttyx->type != tty_type_raw_framebuffer) if (ttyx->type != tty_type_raw_framebuffer)
return; return;
memcpy(&ttyx->typeinfo.raw_framebuffer, fb, sizeof(framebuffer)); 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) if (ttyx->mode == tty_mode_text)
{ {
ttyx->text.width = fb->width / tty_get_font()->char_width; 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) if (ttyx->enabled == false)
return; return;
// TODO 暂时只支持framebuffer
if (ttyx->type != tty_type_raw_framebuffer)
return;
if (ttyx->mode != tty_mode_text) if (ttyx->mode != tty_mode_text)
return; return;
if (ttyx->typeinfo.raw_framebuffer.pixtype == bgr) 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); 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) bool tty_enable(tty *ttyx)
{ {
if (tty_ctrler.enabled[ttyx->id]) if (tty_ctrler.enabled[ttyx->id])

View File

@ -1,11 +1,19 @@
use std::ptr::null_mut; use std::{fmt::Debug, ptr::null_mut};
extern "C" { extern "C" {
fn tty_new(tty_type: u8, mode: u8) -> *mut u8; fn tty_new(tty_type: u8, mode: u8) -> *mut u8;
fn tty_get(id: usize) -> *mut *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_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_enable(tty: *mut u8) -> bool;
fn tty_disable(tty: *mut u8); fn tty_disable(tty: *mut u8);
} }
@ -17,9 +25,31 @@ pub enum Type {
VirtualTerm = 3, VirtualTerm = 3,
} }
impl From<u8> for Type {
fn from(value: u8) -> Self {
match value {
1 => Type::RawFramebuffer,
2 => Type::Display,
3 => Type::VirtualTerm,
_ => Type::Invalid,
}
}
}
pub enum Mode { pub enum Mode {
Text = 0, Invalid = 0,
Graphics = 1, Text = 1,
Graphics = 2,
}
impl From<u8> for Mode {
fn from(value: u8) -> Self {
match value {
1 => Mode::Text,
2 => Mode::Graphics,
_ => Mode::Invalid,
}
}
} }
pub struct Tty { pub struct Tty {
@ -50,6 +80,29 @@ impl Tty {
unsafe { tty_get_id(self.tty_pointer) } 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) { pub fn enable(&self) {
unsafe { tty_enable(self.tty_pointer) }; unsafe { tty_enable(self.tty_pointer) };
} }
@ -82,8 +135,45 @@ impl Tty {
} }
} }
#[derive(Clone, Copy)]
pub struct Color(pub u8, pub u8, pub u8); 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<Color> for u32 { impl From<Color> for u32 {
fn from(value: Color) -> Self { fn from(value: Color) -> Self {
let res = (value.0 as u32) << 16 | (value.1 as u32) << 8 | (value.2 as u32); let res = (value.0 as u32) << 16 | (value.1 as u32) << 8 | (value.2 as u32);
@ -91,14 +181,79 @@ impl From<Color> for u32 {
} }
} }
pub struct Resolution {
pub width: usize,
pub height: usize,
}
#[derive(Clone)]
pub struct MessageSection { pub struct MessageSection {
msg: String, msg: String,
fgcolor: Color, fgcolor: Color,
bgcolor: Color, bgcolor: Color,
} }
#[derive(Clone)]
pub struct Message(Vec<MessageSection>); pub struct Message(Vec<MessageSection>);
impl From<String> 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 { pub struct MessageBuilder {
msg: Message, 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 { pub fn message(mut self, msg: String) -> Self {
self.msg.0.push(MessageSection { self.msg.0.push(MessageSection {
msg, msg,
@ -119,6 +278,14 @@ impl MessageBuilder {
self 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 { pub fn background_color(mut self, color: Color) -> Self {
if let Some(msg) = self.msg.0.last_mut() { if let Some(msg) = self.msg.0.last_mut() {
msg.bgcolor = color; msg.bgcolor = color;
@ -126,6 +293,12 @@ impl MessageBuilder {
self 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 { pub fn foreground_color(mut self, color: Color) -> Self {
if let Some(msg) = self.msg.0.last_mut() { if let Some(msg) = self.msg.0.last_mut() {
msg.fgcolor = color; msg.fgcolor = color;
@ -133,6 +306,17 @@ impl MessageBuilder {
self 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 { pub fn build(self) -> Message {
self.msg self.msg
} }