debug_et_diagnostics/
color.rs1use std::fmt::Display;
2
3const DEFAULT_COLUMNS: usize = 130;
4
5pub fn reset<T: Display>(text: T) -> String {
7 format!("{}\x1b[0m", text)
8}
9
10pub fn fg<T: Display>(text: T, fg: usize) -> String {
12 format!("\x1b[1;38;5;{}m{}", wrap(fg), text)
13}
14pub fn bg<T: Display>(text: T, bg: usize) -> String {
16 format!("\x1b[1;48;5;{}m{}", wrap(bg), text)
17}
18pub fn bgfg<T: Display>(text: T, fore: usize, back: usize) -> String {
22 bg(fg(text, wrap(fore) as usize), wrap(back) as usize)
23}
24pub fn ansi<T: Display>(text: T, fore: usize, back: usize) -> String {
26 reset(bgfg(text, fore as usize, back as usize))
27}
28pub fn pad_columns<T: Display>(text: T) -> String {
30 let text = text.to_string();
31 let cols = term_cols();
32 pad(text, cols)
33}
34pub fn pad<T: Display>(text: T, length: usize) -> String {
36 let text = text.to_string();
37 let len = text
38 .as_bytes()
39 .iter()
40 .map(|c| char::from(*c))
41 .map(|c| {
42 u32::from(c)
43 .to_ne_bytes()
44 .iter()
45 .map(Clone::clone)
46 .filter(|c| *c > 0)
47 .collect::<Vec<u8>>()
48 })
49 .flatten()
50 .count();
51
52 format!(
53 "{}{}",
54 text,
55 " ".repeat(if length > len {
56 length - len
57 } else if len < length {
58 0
59 } else {
60 0
61 })
62 )
63}
64pub fn ansi_clear() -> String {
66 "\x1b[2J\x1b[3J\x1b[H".to_string()
67}
68pub fn fore<T: Display>(text: T, fore: usize) -> String {
70 let (fore, back) = couple(fore);
71 ansi(text, fore as usize, back as usize)
72}
73pub fn back<T: Display>(text: T, back: usize) -> String {
75 let (back, fore) = couple(back);
76 ansi(text, fore as usize, back as usize)
77}
78pub fn auto<T: Display>(word: T) -> String {
80 fore(
81 word.to_string(),
82 bright(
83 u8::from_str_radix(&word.to_string(), 10)
84 .unwrap_or_else(|_| from_display(word.to_string()))
85 .into(),
86 )
87 .into(),
88 )
89}
90pub fn from_display<T: Display>(word: T) -> u8 {
92 from_bytes(word.to_string().as_bytes())
93}
94pub fn rgb_from_display<T: Display>(word: T) -> [u8; 3] {
96 rgb_from_bytes(word.to_string().as_bytes())
97}
98
99pub fn from_bytes(bytes: &[u8]) -> u8 {
101 let mut color: u8 = 0;
102 for rgb in rgb_from_bytes(bytes) {
103 color ^= rgb
104 }
105 color
106}
107pub fn rgb_from_bytes(bytes: &[u8]) -> [u8; 3] {
110 let mut color: [u8; 3] = [0, 0, 0];
111 let mut iter = 0;
112 while iter < 3 {
113 for (index, byte) in bytes.iter().enumerate() {
114 color[index % 3] ^= *byte
115 }
116 iter += 1;
117 }
118 color
119}
120
121pub fn couple(color: usize) -> (u8, u8) {
126 let fore = bright(wrap(color));
127 let back = invert_bw(fore);
128 (fore, back)
129}
130
131pub fn invert_bw(color: u8) -> u8 {
133 match color {
134 0 | 8 | 16..21 | 52..61 | 88..93 | 232..239 => 231,
135 _ => 16,
136 }
137}
138pub fn bright(color: u8) -> u8 {
140 match color {
141 0 | 8 => color + 100,
142 16..21 => color + 100,
143 52..61 => color + 40,
144 88..93 => color + 50,
145 232..239 => 249,
146 _ => color,
147 }
148}
149
150pub fn wrap(color: usize) -> u8 {
152 (if color > 0 { color % 255 } else { color }) as u8
153}
154
155fn io_term_cols() -> std::io::Result<usize> {
164 if let Ok(cols) = std::env::var("COLUMNS") {
165 if let Ok(cols) = usize::from_str_radix(&cols, 10) {
166 return Ok(cols);
167 }
168 }
169 use std::process::{Command, Stdio};
170 let mut cmd = Command::new("/bin/stty");
171 let cmd = cmd.args(vec!["-a"]);
172 let cmd = cmd.stdin(Stdio::inherit());
173 let cmd = cmd.stdout(Stdio::piped());
174 let cmd = cmd.stderr(Stdio::piped());
175 let child = cmd.spawn()?;
176 let output = child.wait_with_output()?;
177 let lines = String::from_utf8_lossy(&output.stdout)
178 .to_string()
179 .lines()
180 .map(String::from)
181 .collect::<Vec<String>>();
182 let lines = lines[0]
183 .split(';')
184 .map(String::from)
185 .collect::<Vec<String>>();
186 if lines.len() > 2 {
187 let fields = lines[2]
188 .split(' ')
189 .map(String::from)
190 .collect::<Vec<String>>();
191 if let Ok(cols) = usize::from_str_radix(&fields[1], 10) {
192 return Ok(cols);
193 }
194 }
195 Ok(DEFAULT_COLUMNS)
196}
197
198pub fn term_cols() -> usize {
202 io_term_cols().unwrap_or_else(|_| DEFAULT_COLUMNS)
203}