Next Generation WASM Microkernel Operating System
wasm
os
rust
microkernel
1// Copyright 2025 Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use core::fmt;
9
10pub trait SetColor {
11 fn set_fg_color(&mut self, color: Color);
12 fn fg_color(&self) -> Color;
13
14 /// Sets bold text.
15 ///
16 /// This may brighten a text color if bold text is not supported.
17 fn set_bold(&mut self, bold: bool);
18
19 fn with_bold(&mut self) -> WithBold<'_, Self>
20 where
21 Self: fmt::Write + Sized,
22 {
23 self.set_bold(true);
24 WithBold { writer: self }
25 }
26
27 #[must_use]
28 fn with_fg_color(&mut self, color: Color) -> WithFgColor<'_, Self>
29 where
30 Self: fmt::Write + Sized,
31 {
32 let prev_color = self.fg_color();
33 self.set_fg_color(color);
34 WithFgColor {
35 writer: self,
36 prev_color,
37 }
38 }
39}
40
41#[derive(Copy, Clone, Debug, Eq, PartialEq)]
42#[repr(usize)]
43pub enum Color {
44 Black = 0,
45 Red,
46 Green,
47 Yellow,
48 Blue,
49 Magenta,
50 Cyan,
51 White,
52 Default,
53 BrightBlack,
54 BrightRed,
55 BrightGreen,
56 BrightYellow,
57 BrightBlue,
58 BrightMagenta,
59 BrightCyan,
60 BrightWhite,
61}
62
63#[derive(Debug, Eq, PartialEq)]
64pub struct WithFgColor<'writer, W>
65where
66 W: fmt::Write + SetColor,
67{
68 writer: &'writer mut W,
69 prev_color: Color,
70}
71
72#[derive(Debug, Eq, PartialEq)]
73pub struct WithBold<'writer, W>
74where
75 W: fmt::Write + SetColor,
76{
77 writer: &'writer mut W,
78}
79
80#[derive(Copy, Clone, Debug, Eq, PartialEq)]
81pub struct AnsiEscapes<W> {
82 writer: W,
83 current_fg: Color,
84}
85
86impl<W: SetColor> SetColor for &'_ mut W {
87 #[inline]
88 fn set_fg_color(&mut self, color: Color) {
89 W::set_fg_color(self, color);
90 }
91
92 #[inline]
93 fn fg_color(&self) -> Color {
94 W::fg_color(self)
95 }
96
97 #[inline]
98 fn set_bold(&mut self, bold: bool) {
99 W::set_bold(self, bold);
100 }
101}
102
103// === impl WithFgColor ===
104
105impl<W> fmt::Write for WithFgColor<'_, W>
106where
107 W: fmt::Write + SetColor,
108{
109 #[inline]
110 fn write_str(&mut self, s: &str) -> fmt::Result {
111 self.writer.write_str(s)
112 }
113
114 #[inline]
115 fn write_char(&mut self, c: char) -> fmt::Result {
116 self.writer.write_char(c)
117 }
118
119 #[inline]
120 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
121 self.writer.write_fmt(args)
122 }
123}
124
125impl<W> Drop for WithFgColor<'_, W>
126where
127 W: fmt::Write + SetColor,
128{
129 fn drop(&mut self) {
130 self.writer.set_fg_color(self.prev_color);
131 }
132}
133
134// === impl WithBold ===
135
136impl<W> fmt::Write for WithBold<'_, W>
137where
138 W: fmt::Write + SetColor,
139{
140 #[inline]
141 fn write_str(&mut self, s: &str) -> fmt::Result {
142 self.writer.write_str(s)
143 }
144
145 #[inline]
146 fn write_char(&mut self, c: char) -> fmt::Result {
147 self.writer.write_char(c)
148 }
149
150 #[inline]
151 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
152 self.writer.write_fmt(args)
153 }
154}
155
156impl<W> Drop for WithBold<'_, W>
157where
158 W: fmt::Write + SetColor,
159{
160 fn drop(&mut self) {
161 self.writer.set_bold(false);
162 }
163}
164
165// === impl AnsiEscapes ===
166
167impl<W> AnsiEscapes<W> {
168 pub const fn new(writer: W) -> Self {
169 Self {
170 writer,
171 current_fg: Color::Default,
172 }
173 }
174}
175
176impl<W> fmt::Write for AnsiEscapes<W>
177where
178 W: fmt::Write,
179{
180 #[inline]
181 fn write_str(&mut self, s: &str) -> fmt::Result {
182 self.writer.write_str(s)
183 }
184
185 #[inline]
186 fn write_char(&mut self, c: char) -> fmt::Result {
187 self.writer.write_char(c)
188 }
189
190 #[inline]
191 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
192 self.writer.write_fmt(args)
193 }
194}
195
196impl<W> AnsiEscapes<W> {
197 const ANSI_FG_COLOR_TABLE: [&'static str; 17] = [
198 "30", // black
199 "31", // red
200 "32", // green
201 "33", // yellow
202 "34", // blue
203 "35", // magenta
204 "36", // cyan
205 "37", // white
206 "39", // default
207 "90", // bright black
208 "91", // bright red
209 "92", // bright green
210 "93", // bright yellow
211 "94", // bright blue
212 "95", // bright magenta
213 "96", // bright cyan
214 "97", // bright white
215 ];
216
217 fn fg_code(&self) -> &'static str {
218 Self::ANSI_FG_COLOR_TABLE[self.current_fg as usize]
219 }
220}
221
222impl<W: fmt::Write> SetColor for AnsiEscapes<W> {
223 fn set_fg_color(&mut self, color: Color) {
224 self.current_fg = color;
225 let _ = write!(self.writer, "\x1b[{}m", self.fg_code());
226 }
227
228 fn fg_color(&self) -> Color {
229 self.current_fg
230 }
231
232 fn set_bold(&mut self, bold: bool) {
233 let _ = if bold {
234 self.writer.write_str("\x1b[1m")
235 } else {
236 self.writer.write_str("\x1b[22m")
237 };
238 }
239}