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