1#![cfg_attr(not(test), no_std)]
44
45
46use core::{fmt, slice, str};
47
48#[macro_export]
75macro_rules! mode {
76 ($($tt:tt)*) => {
77 $crate::__mode!([] $($tt)*)
78 };
79}
80
81#[doc(hidden)]
82#[macro_export]
83macro_rules! __mode {
84 ([$($code:expr,)*] $ground:ident $space:ident $index:expr; $($tail:tt)*) => {
86 $crate::__mode!([
87 $($code,)*
88 $crate::__FG_or_BG::$ground.__byte,
89 $crate::__RGB_or_PAL::$space.__byte,
90 { let index: u8 = $index; index },
91 ] $($tail)*)
92 };
93 ([$($code:expr,)*] $ground:ident $space:ident $index:expr) => {
94 $crate::__mode!([
95 $($code,)*
96 $crate::__FG_or_BG::$ground.__byte,
97 $crate::__RGB_or_PAL::$space.__byte,
98 { let index: u8 = $index; index },
99 ])
100 };
101
102 ([$($code:expr,)*] $ground:ident $space:ident $red:expr, $green:expr, $blue:expr; $($tail:tt)*) => {
104 $crate::__mode!([
105 $($code,)*
106 $crate::__FG_or_BG::$ground.__byte,
107 $crate::__RGB_or_PAL::$space.__byte,
108 { let red: u8 = $red; red },
109 { let green: u8 = $green; green },
110 { let blue: u8 = $blue; blue },
111 ] $($tail)*)
112 };
113 ([$($code:expr,)*] $ground:ident $space:ident $red:expr, $green:expr, $blue:expr) => {
114 $crate::__mode!([
115 $($code,)*
116 $crate::__FG_or_BG::$ground.__byte,
117 $crate::__RGB_or_PAL::$space.__byte,
118 { let red: u8 = $red; red },
119 { let green: u8 = $green; green },
120 { let blue: u8 = $blue; blue },
121 ])
122 };
123
124 ([$($code:expr,)*] $name:ident; $($tail:tt)*) => {
126 $crate::__mode!([
127 $($code,)*
128 $crate::codes::$name.__byte,
129 ] $($tail)*)
130 };
131 ([$($code:expr,)*] $name:ident) => {
132 $crate::__mode!([
133 $($code,)*
134 $crate::codes::$name.__byte,
135 ])
136 };
137
138 ([$($code:expr,)*] {$v:expr}; $($tail:tt)*) => {
140 $crate::__mode!([
141 $($code,)*
142 { let v: $crate::Code = $v; v.__byte },
143 ] $($tail)*)
144 };
145 ([$($code:expr,)*] {$v:expr}) => {
146 $crate::__mode!([
147 $($code,)*
148 { let v: $crate::Code = $v; v.__byte },
149 ])
150 };
151
152 ([$($code:expr,)*]) => {
154 $crate::Print { __codes: [$($code),*] }
155 };
156}
157
158#[derive(Copy, Clone, Eq, PartialEq)]
160#[repr(transparent)]
161pub struct Code {
162 #[doc(hidden)]
163 pub __byte: u8,
164}
165
166#[doc(hidden)]
167#[allow(non_snake_case)]
168pub mod __FG_or_BG {
169 use super::Code;
170
171 pub const FG: Code = Code { __byte: 38 };
173 pub const BG: Code = Code { __byte: 48 };
175}
176
177#[doc(hidden)]
178#[allow(non_snake_case)]
179pub mod __RGB_or_PAL {
180 use super::Code;
181
182 pub const PAL: Code = Code { __byte: 5 };
184 pub const RGB: Code = Code { __byte: 2 };
186}
187
188pub mod codes {
192 use super::Code;
193
194 pub const BOLD: Code = Code { __byte: 1 };
196 pub const DIM: Code = Code { __byte: 2 };
198 pub const ITALIC: Code = Code { __byte: 3 };
200 pub const UNDERLINE: Code = Code { __byte: 4 };
202 pub const BLINK: Code = Code { __byte: 5 };
204 pub const INVERSE: Code = Code { __byte: 7 };
206 pub const HIDDEN: Code = Code { __byte: 8 };
208 pub const STRIKE: Code = Code { __byte: 9 };
210
211 pub const RESET: Code = Code { __byte: 0 };
213 pub const RESET_WEIGHT: Code = Code { __byte: 22 };
215 pub const RESET_ITALIC: Code = Code { __byte: 23 };
217 pub const RESET_UNDERLINE: Code = Code { __byte: 24 };
219 pub const RESET_BLINK: Code = Code { __byte: 25 };
221 pub const RESET_INVERSE: Code = Code { __byte: 27 };
223 pub const RESET_HIDDEN: Code = Code { __byte: 28 };
225 pub const RESET_STRIKE: Code = Code { __byte: 29 };
227
228 pub const BLACK: Code = Code { __byte: 30 };
230 pub const RED: Code = Code { __byte: 31 };
232 pub const GREEN: Code = Code { __byte: 32 };
234 pub const YELLOW: Code = Code { __byte: 33 };
236 pub const BLUE: Code = Code { __byte: 34 };
238 pub const MAGENTA: Code = Code { __byte: 35 };
240 pub const CYAN: Code = Code { __byte: 36 };
242 pub const WHITE: Code = Code { __byte: 37 };
244 pub const DEFAULT: Code = Code { __byte: 39 };
246
247 pub const BLACK_BG: Code = Code { __byte: 40 };
249 pub const RED_BG: Code = Code { __byte: 41 };
251 pub const GREEN_BG: Code = Code { __byte: 42 };
253 pub const YELLOW_BG: Code = Code { __byte: 43 };
255 pub const BLUE_BG: Code = Code { __byte: 44 };
257 pub const MAGENTA_BG: Code = Code { __byte: 45 };
259 pub const CYAN_BG: Code = Code { __byte: 46 };
261 pub const WHITE_BG: Code = Code { __byte: 47 };
263 pub const DEFAULT_BG: Code = Code { __byte: 49 };
265
266 pub const BRIGHT_BLACK: Code = Code { __byte: 90 };
268 pub const BRIGHT_RED: Code = Code { __byte: 91 };
270 pub const BRIGHT_GREEN: Code = Code { __byte: 92 };
272 pub const BRIGHT_YELLOW: Code = Code { __byte: 93 };
274 pub const BRIGHT_BLUE: Code = Code { __byte: 94 };
276 pub const BRIGHT_MAGENTA: Code = Code { __byte: 95 };
278 pub const BRIGHT_CYAN: Code = Code { __byte: 96 };
280 pub const BRIGHT_WHITE: Code = Code { __byte: 97 };
282
283 pub const BRIGHT_BLACK_BG: Code = Code { __byte: 100 };
285 pub const BRIGHT_RED_BG: Code = Code { __byte: 101 };
287 pub const BRIGHT_GREEN_BG: Code = Code { __byte: 102 };
289 pub const BRIGHT_YELLOW_BG: Code = Code { __byte: 103 };
291 pub const BRIGHT_BLUE_BG: Code = Code { __byte: 104 };
293 pub const BRIGHT_MAGENTA_BG: Code = Code { __byte: 105 };
295 pub const BRIGHT_CYAN_BG: Code = Code { __byte: 106 };
297 pub const BRIGHT_WHITE_BG: Code = Code { __byte: 107 };
299}
300
301pub use self::codes::*;
302
303impl fmt::Display for Code {
304 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305 let mut buf = [0u8; 8];
306 f.write_str(display(slice::from_ref(&self.__byte), &mut buf).ok_or(fmt::Error)?)?;
307 Ok(())
308 }
309}
310
311impl fmt::Debug for Code {
312 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
313 write!(f, "\"\\x1b[{}m\"", self.__byte)
314 }
315}
316
317pub struct Print<T: AsRef<[u8]>> {
321 #[doc(hidden)]
322 pub __codes: T,
323}
324
325impl<T: AsRef<[u8]>> Print<T> {
326 pub fn erase<'a>(&'a self) -> Print<&'a [u8]> {
328 Print { __codes: self.__codes.as_ref() }
329 }
330}
331
332impl<T: AsRef<[u8]>> fmt::Display for Print<T> {
333 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
334 let codes = self.__codes.as_ref();
335 if codes.len() > 0 {
336 let mut buf = [0u8; 64];
337 f.write_str(display(codes, &mut buf).ok_or(fmt::Error)?)?;
338 }
339 Ok(())
340 }
341}
342
343impl<T: AsRef<[u8]>> fmt::Debug for Print<T> {
344 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
345 debug(self.__codes.as_ref(), f)
346 }
347}
348
349#[inline(never)]
350fn debug(codes: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
351 if codes.len() > 0 {
352 write!(f, "\"\\x1b[")?;
353 for i in 0..codes.len() {
354 let suffix = if i + 1 == codes.len() { 'm' } else { ';' };
355 write!(f, "{}{}", codes[i], suffix)?;
356 }
357 write!(f, "\"")?;
358 }
359 Ok(())
360}
361
362#[inline]
363fn display_code(mut code: u8, suffix: u8, buf: &mut [u8]) -> usize {
364 if buf.len() < 4 {
365 return 0;
366 }
367
368 let mut i = 0;
369 if code >= 100 {
370 buf[i] = b'0' + code / 100;
371 code = code % 100;
372 i += 1;
373 }
374 if code >= 10 {
375 buf[i] = b'0' + code / 10;
376 code = code % 10;
377 i += 1;
378 }
379 buf[i] = b'0' + code;
380 i += 1;
381 buf[i] = suffix;
382 i += 1;
383 return i;
384}
385
386#[inline(never)]
387fn display<'a>(codes: &[u8], buf: &'a mut [u8]) -> Option<&'a str> {
388 if buf.len() < 3 {
389 return None;
390 }
391 buf[0] = 0x1b;
392 buf[1] = b'[';
393 let mut total = 2;
394 {
395 let mut buf = &mut buf[2..];
396 for i in 0..codes.len() {
397 let suffix = if i + 1 == codes.len() { b'm' } else { b';' };
398 let skip = display_code(codes[i], suffix, buf);
399 if skip == 0 {
400 return None;
401 }
402 total += skip;
403 buf = &mut buf[skip..];
404 }
405 }
406 let buf = &buf.get(..total)?;
407 unsafe { Some(str::from_utf8_unchecked(buf)) }
408}
409
410#[cfg(test)]
411mod tests;