1 //! Write ANSI escape code colored text
2 
3 use std::io::Write;
4 
main() -> Result<(), lexopt::Error>5 fn main() -> Result<(), lexopt::Error> {
6     let args = Args::parse()?;
7     let stdout = std::io::stdout();
8     let mut stdout = stdout.lock();
9 
10     for fixed in 0..16 {
11         let color = anstyle::Ansi256Color(fixed)
12             .into_ansi()
13             .expect("4-bit range used");
14         let style = style(color, args.layer, args.effects);
15         let _ = print_number(&mut stdout, fixed, style);
16         if fixed == 7 || fixed == 15 {
17             let _ = writeln!(&mut stdout);
18         }
19     }
20 
21     for fixed in 16..232 {
22         let col = (fixed - 16) % 36;
23         if col == 0 {
24             let _ = writeln!(stdout);
25         }
26         let color = anstyle::Ansi256Color(fixed);
27         let style = style(color, args.layer, args.effects);
28         let _ = print_number(&mut stdout, fixed, style);
29     }
30 
31     let _ = writeln!(stdout);
32     let _ = writeln!(stdout);
33     for fixed in 232..=255 {
34         let color = anstyle::Ansi256Color(fixed);
35         let style = style(color, args.layer, args.effects);
36         let _ = print_number(&mut stdout, fixed, style);
37     }
38 
39     let _ = writeln!(stdout);
40 
41     Ok(())
42 }
43 
style( color: impl Into<anstyle::Color>, layer: Layer, effects: anstyle::Effects, ) -> anstyle::Style44 fn style(
45     color: impl Into<anstyle::Color>,
46     layer: Layer,
47     effects: anstyle::Effects,
48 ) -> anstyle::Style {
49     let color = color.into();
50     (match layer {
51         Layer::Fg => anstyle::Style::new().fg_color(Some(color)),
52         Layer::Bg => anstyle::Style::new().bg_color(Some(color)),
53         Layer::Underline => anstyle::Style::new().underline_color(Some(color)),
54     }) | effects
55 }
56 
print_number( stdout: &mut std::io::StdoutLock<'_>, fixed: u8, style: anstyle::Style, ) -> std::io::Result<()>57 fn print_number(
58     stdout: &mut std::io::StdoutLock<'_>,
59     fixed: u8,
60     style: anstyle::Style,
61 ) -> std::io::Result<()> {
62     write!(stdout, "{style}{fixed:>3X}{style:#}",)
63 }
64 
65 #[derive(Default)]
66 struct Args {
67     effects: anstyle::Effects,
68     layer: Layer,
69 }
70 
71 #[derive(Copy, Clone, Default)]
72 enum Layer {
73     #[default]
74     Fg,
75     Bg,
76     Underline,
77 }
78 
79 impl Args {
parse() -> Result<Self, lexopt::Error>80     fn parse() -> Result<Self, lexopt::Error> {
81         use lexopt::prelude::*;
82 
83         let mut res = Args::default();
84 
85         let mut args = lexopt::Parser::from_env();
86         while let Some(arg) = args.next()? {
87             match arg {
88                 Long("layer") => {
89                     res.layer = args.value()?.parse_with(|s| match s {
90                         "fg" => Ok(Layer::Fg),
91                         "bg" => Ok(Layer::Bg),
92                         "underline" => Ok(Layer::Underline),
93                         _ => Err("expected values fg, bg, underline"),
94                     })?;
95                 }
96                 Long("effect") => {
97                     const EFFECTS: [(&str, anstyle::Effects); 12] = [
98                         ("bold", anstyle::Effects::BOLD),
99                         ("dimmed", anstyle::Effects::DIMMED),
100                         ("italic", anstyle::Effects::ITALIC),
101                         ("underline", anstyle::Effects::UNDERLINE),
102                         ("double_underline", anstyle::Effects::DOUBLE_UNDERLINE),
103                         ("curly_underline", anstyle::Effects::CURLY_UNDERLINE),
104                         ("dotted_underline", anstyle::Effects::DOTTED_UNDERLINE),
105                         ("dashed_underline", anstyle::Effects::DASHED_UNDERLINE),
106                         ("blink", anstyle::Effects::BLINK),
107                         ("invert", anstyle::Effects::INVERT),
108                         ("hidden", anstyle::Effects::HIDDEN),
109                         ("strikethrough", anstyle::Effects::STRIKETHROUGH),
110                     ];
111                     let effect = args.value()?.parse_with(|s| {
112                         EFFECTS
113                             .into_iter()
114                             .find(|(name, _)| *name == s)
115                             .map(|(_, effect)| effect)
116                             .ok_or_else(|| {
117                                 format!(
118                                     "expected one of {}",
119                                     EFFECTS
120                                         .into_iter()
121                                         .map(|(n, _)| n)
122                                         .collect::<Vec<_>>()
123                                         .join(", ")
124                                 )
125                             })
126                     })?;
127                     res.effects = res.effects.insert(effect);
128                 }
129                 _ => return Err(arg.unexpected()),
130             }
131         }
132         Ok(res)
133     }
134 }
135