color_string/
font.rs

1use std::borrow::Cow;
2use std::fmt::{Display, Formatter};
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5pub enum Font {
6    /// 重置样式
7    Reset,
8    /// 字体加粗
9    Bold,
10    RBold,
11    /// 下划线
12    Underline,
13    RUnderline,
14    /// 斜体
15    Italic,
16    RItalic,
17    /// 反色(前景色背景色交换)
18    Reverse,
19    RReverse,
20    /// 删除线
21    Delete,
22    RDelete,
23    /// 黑色字体
24    Black,
25    RBlack,
26    /// 红色字体
27    Red,
28    RRed,
29    /// 绿色字体
30    Green,
31    RGreen,
32    /// 黄色字体
33    Yellow,
34    RYellow,
35    /// 蓝色字体
36    Blue,
37    RBlue,
38    /// 紫色字体
39    Purple,
40    RPurple,
41    /// 青色字体
42    Cyan,
43    RCyan,
44    /// 灰色字体
45    Grey,
46    RGrey,
47    /// 黑色背景
48    BgBlack,
49    RBgBlack,
50    /// 红色背景
51    BgRed,
52    RBgRed,
53    /// 绿色背景
54    BgGreen,
55    RBgGreen,
56    /// 黄色背景
57    BgYellow,
58    RBgYellow,
59    /// 蓝色背景
60    BgBlue,
61    RBgBlue,
62    /// 紫色背景
63    BgPurple,
64    RBgPurple,
65    /// 青色背景
66    BgCyan,
67    RBgCyan,
68    /// 灰色背景
69    BgGrey,
70    RBgGrey,
71    /// 字体颜色 RGB
72    Color(u8, u8, u8),
73    RColor(u8, u8, u8),
74    /// 背景颜色 RGB
75    BgColor(u8, u8, u8),
76    RBgColor(u8, u8, u8),
77}
78
79impl Font {
80    pub fn as_str(&self) -> Cow<'static, str> {
81        match self {
82            Font::Reset => Cow::Borrowed("0"),
83            Font::Bold => Cow::Borrowed("1"),
84            Font::RBold => Cow::Borrowed("0;1"),
85            Font::Italic => Cow::Borrowed("3"),
86            Font::RItalic => Cow::Borrowed("0;3"),
87            Font::Underline => Cow::Borrowed("4"),
88            Font::RUnderline => Cow::Borrowed("0;4"),
89            Font::Reverse => Cow::Borrowed("7"),
90            Font::RReverse => Cow::Borrowed("0;7"),
91            Font::Delete => Cow::Borrowed("9"),
92            Font::RDelete => Cow::Borrowed("0;9"),
93            Font::Black => Cow::Borrowed("30"),
94            Font::RBlack => Cow::Borrowed("0;30"),
95            Font::Red => Cow::Borrowed("31"),
96            Font::RRed => Cow::Borrowed("0;31"),
97            Font::Green => Cow::Borrowed("32"),
98            Font::RGreen => Cow::Borrowed("0;32"),
99            Font::Yellow => Cow::Borrowed("33"),
100            Font::RYellow => Cow::Borrowed("0;33"),
101            Font::Blue => Cow::Borrowed("34"),
102            Font::RBlue => Cow::Borrowed("0;34"),
103            Font::Purple => Cow::Borrowed("35"),
104            Font::RPurple => Cow::Borrowed("0;35"),
105            Font::Cyan => Cow::Borrowed("36"),
106            Font::RCyan => Cow::Borrowed("0;36"),
107            Font::Grey => Cow::Borrowed("37"),
108            Font::RGrey => Cow::Borrowed("0;37"),
109            Font::BgBlack => Cow::Borrowed("40"),
110            Font::RBgBlack => Cow::Borrowed("0;40"),
111            Font::BgRed => Cow::Borrowed("41"),
112            Font::RBgRed => Cow::Borrowed("0;41"),
113            Font::BgGreen => Cow::Borrowed("42"),
114            Font::RBgGreen => Cow::Borrowed("0;42"),
115            Font::BgYellow => Cow::Borrowed("43"),
116            Font::RBgYellow => Cow::Borrowed("0;43"),
117            Font::BgBlue => Cow::Borrowed("44"),
118            Font::RBgBlue => Cow::Borrowed("0;44"),
119            Font::BgPurple => Cow::Borrowed("45"),
120            Font::RBgPurple => Cow::Borrowed("0;45"),
121            Font::BgCyan => Cow::Borrowed("46"),
122            Font::RBgCyan => Cow::Borrowed("0;46"),
123            Font::BgGrey => Cow::Borrowed("47"),
124            Font::RBgGrey => Cow::Borrowed("0;47"),
125            Font::Color(r, g, b) => Cow::Owned(format!("38;2;{};{};{}", r, g, b)),
126            Font::RColor(r, g, b) => Cow::Owned(format!("0;38;2;{};{};{}", r, g, b)),
127            Font::BgColor(r, g, b) => Cow::Owned(format!("48;2;{};{};{}", r, g, b)),
128            Font::RBgColor(r, g, b) => Cow::Owned(format!("0;48;2;{};{};{}", r, g, b)),
129        }
130    }
131}
132impl Display for Font {
133    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
134        write!(f, "\x1b[{}m", self.as_str())
135    }
136}
137
138#[test]
139fn font_is_work() {
140    assert_eq!("\x1b[30m", format!("{}", Font::Black));
141    assert_eq!("\x1b[38;2;1;2;3m", format!("{}", Font::Color(1, 2, 3)));
142}
143
144/// 组合多种字体
145/// # Example
146/// ```
147/// use color_string::fonts;
148/// use color_string::Font::*;
149/// let fonts = fonts!(Red, Bold, Underline, BgColor(1, 2, 3));
150/// assert_eq!("\x1b[31;1;4;48;2;1;2;3m", fonts)
151/// ```
152#[macro_export]
153macro_rules! fonts {
154    ($ ($font:expr),*) => {{
155        let mut s = String::new();
156        $crate::wf!(&mut s, $($font),*);
157        s
158    }};
159}
160
161/// 写入多种字体
162/// # Example
163/// ```
164/// use color_string::wf;
165/// use color_string::Font::*;
166/// let mut fonts = String::new();
167/// wf!(&mut fonts, Red, Bold, Underline, BgColor(1, 2, 3));
168/// println!("{} hello world! {}", fonts, Reset);
169/// assert_eq!("\x1b[31;1;4;48;2;1;2;3m", fonts)
170/// ```
171#[macro_export]
172macro_rules! wf {
173    ($s:expr, $($font:expr),*) => {{
174        use std::fmt::Write;
175        $s.push_str("\x1b[");
176                $(
177            let s = $font.as_str();
178            if s.starts_with("\x1b[") {
179                write!($s, "{};", &s[2..s.len() - 1]).unwrap();
180            }else {
181                write!($s, "{};", s).unwrap();
182            }
183        )*
184        $s.pop();
185        $s.push('m');
186    }};
187}
188
189pub trait FontTool {
190    fn reset(&mut self) -> &Self;
191
192    fn no_reset(self) -> Self;
193
194    fn none_font(&self) -> Self;
195}
196
197impl FontTool for String {
198    fn reset(&mut self) -> &Self {
199        let reset = Font::Reset.to_string();
200        if !self.ends_with(&reset) {
201            self.push_str(&reset)
202        }
203        self
204    }
205
206    fn no_reset(mut self) -> Self {
207        if self.ends_with("\x1b[0m") {
208            self.truncate(self.len() - 4);
209        }
210        self
211    }
212
213    fn none_font(&self) -> Self {
214        none_font(self)
215    }
216}
217
218pub fn none_font(s: &str) -> String {
219    let mut buf = String::new();
220    let mut flag = false;
221    for c in s.chars() {
222        match c {
223            '\x1b' => flag = true,
224            'm' if flag => flag = false,
225            _ if !flag => buf.push(c),
226            _ => {}
227        }
228    }
229    buf
230}
231
232#[test]
233fn aaa() {
234    use crate::cs;
235    use crate::Colored;
236    let s = cs!(Font::Red => "hello");
237    println!("{s}");
238    println!("{}", s.none_font());
239    println!("{}456", "123".red().no_reset());
240}