1use colored::{Color::TrueColor, Colorize};
5use std::fmt::{Display, Formatter, Result as FmtResult};
6
7pub struct Decorated<'a, T: Display> {
8 data: &'a T,
9 prefix: Option<String>,
10 color: Option<colored::Color>,
11}
12
13impl<'a, T: Display> Decorated<'a, T> {
14 pub fn new(data: &'a T) -> Self {
15 Decorated {
16 data,
17 prefix: None,
18 color: None,
19 }
20 }
21
22 pub fn true_color(&mut self, r: u8, g: u8, b: u8) -> Self {
23 Decorated {
24 data: self.data,
25 prefix: self.prefix.clone(),
26 color: Some(TrueColor { r, g, b }),
27 }
28 }
29}
30
31impl<'a, T: Display> Display for Decorated<'a, T> {
32 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
33 let prefix = self.prefix.clone().unwrap_or_default();
34
35 if f.alternate() {
36 let formatted = format!("{}{:#}", prefix, self.data);
37 if let Some(color) = self.color {
38 write!(f, "{}", formatted.color(color))
39 } else {
40 write!(f, "{}", formatted)
41 }
42 } else {
43 write!(f, "{}", prefix)?;
44 self.data.fmt(f)
45 }
46 }
47}
48
49pub trait Themed: Display + Sized {
50 fn ty(&self) -> Decorated<'_, Self> {
51 Decorated::new(self).true_color(102, 217, 239)
52 }
53 fn target(&self) -> Decorated<'_, Self> {
54 Decorated::new(self).true_color(174, 129, 255)
55 }
56 fn keyword(&self) -> Decorated<'_, Self> {
57 Decorated::new(self).true_color(249, 38, 114)
58 }
59 fn symbol(&self) -> Decorated<'_, Self> {
60 Decorated::new(self).true_color(166, 226, 46)
61 }
62 fn at_symbol(&self) -> Decorated<'_, Self> {
63 let mut decorated = self.symbol();
64 decorated.prefix = Some("@".to_string());
65 decorated
66 }
67
68 fn comment(&self) -> Decorated<'_, Self> {
69 Decorated::new(self).true_color(117, 113, 94)
70 }
71
72 fn instruction(&self) -> Decorated<'_, Self> {
73 Decorated::new(self).true_color(102, 217, 239)
74 }
75}
76
77impl<T: Display> Themed for T {}
78
79impl<'a, T: Display> From<&'a T> for Decorated<'a, T> {
80 fn from(value: &'a T) -> Self {
81 Decorated::new(value)
82 }
83}
84
85impl<'a, T: Display> From<&'a mut T> for Decorated<'a, T> {
86 fn from(value: &'a mut T) -> Self {
87 Decorated::new(value)
88 }
89}
90
91impl<T: Display> From<T> for Decorated<'_, T> {
92 fn from(value: T) -> Self {
93 Decorated::new(Box::leak(Box::new(value)))
94 }
95}
96
97#[macro_export]
98macro_rules! show {
99 ($fmt:expr $(, $arg:expr)* $(,)?) => {
100 {
101 $($arg.fmt($fmt)?;)*
102 }
103 };
104}
105
106#[macro_export]
107macro_rules! show_instruction {
108 ($fmt:expr, $inst:expr $(, $arg:expr)* $(,)?) => {
109 {
110 $inst.instruction().fmt($fmt)?;
111 $($arg.fmt($fmt)?;)*
112 }
113 };
114}
115
116pub use show;
117pub use show_instruction;
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_decorated() {
125 let value = 42;
126 let decorated = Decorated::new(&value).true_color(255, 0, 0);
127 println!("{}", decorated);
128 println!("{:#}", decorated);
129 }
130
131 #[test]
132 fn test_themed() {
133 let value = "test";
134 println!("{:#}", value.ty());
135 println!("{:#}", value.target());
136 println!("{:#}", value.keyword());
137 println!("{:#}", value.symbol());
138 println!("{:#}", value.at_symbol());
139 println!("{:#}", value.comment());
140 println!("{:#}", value.instruction());
141 }
142}