debug_et_diagnostics/
color.rs1use std::fmt::Display;
2
3const DEFAULT_COLUMNS: usize = 130;
4
5
6pub fn reset<T: Display>(text: T) -> String {
8 format!("{}\x1b[0m", text)
9}
10
11pub fn fg<T: Display>(text: T, fg: usize) -> String {
13 format!("\x1b[1;38;5;{}m{}", wrap(fg), text)
14}
15pub fn bg<T: Display>(text: T, bg: usize) -> String {
17 format!("\x1b[1;48;5;{}m{}", wrap(bg), text)
18}
19pub fn bgfg<T: Display>(text: T, fore: usize, back: usize) -> String {
23 bg(fg(text, wrap(fore) as usize), wrap(back) as usize)
24}
25pub fn ansi<T: Display>(text: T, fore: usize, back: usize) -> String {
27 reset(bgfg(text, fore as usize, back as usize))
28}
29pub fn pad_columns<T: Display>(text: T) -> String {
31 let text = text.to_string();
32 let len = text.len();
33 let cols = term_cols();
34 format!(
35 "{}{}",
36 text,
37 " ".repeat(if cols > len { cols - len } else { 0 })
38 )
39}
40pub fn ansi_clear() -> String {
42 "\x1b[2J\x1b[3J\x1b[H".to_string()
43}
44pub fn fore<T: Display>(text: T, fore: usize) -> String {
46 let (fore, back) = couple(fore);
47 ansi(text, fore as usize, back as usize)
48}
49pub fn back<T: Display>(text: T, back: usize) -> String {
51 let (back, fore) = couple(back);
52 ansi(text, fore as usize, back as usize)
53}
54pub fn auto<T: Display>(word: T) -> String {
56 fore(
57 word.to_string(),
58 u8::from_str_radix(&word.to_string(), 10)
59 .unwrap_or_else(|_| from_string(word.to_string()))
60 .into(),
61 )
62}
63pub fn from_string<T: Display>(word: T) -> u8 {
65 from_bytes(word.to_string().as_bytes())
66}
67pub fn rgb_from_string<T: Display>(word: T) -> [u8; 3] {
69 rgb_from_bytes(word.to_string().as_bytes())
70}
71
72pub fn from_bytes(bytes: &[u8]) -> u8 {
74 let mut color: u8 = 0;
75 for rgb in rgb_from_bytes(bytes) {
76 color ^= rgb
77 }
78 color
79}
80pub fn rgb_from_bytes(bytes: &[u8]) -> [u8; 3] {
83 let mut color: [u8; 3] = [0, 0, 0];
84 let mut iter = 0;
85 while iter < 3 {
86 for (index, byte) in bytes.iter().enumerate() {
87 color[index % 3] ^= *byte
88 }
89 iter += 1;
90 }
91 color
92}
93
94pub fn couple(color: usize) -> (u8, u8) {
99 let fore = wrap(color);
100 let back = invert_bw(fore);
101 (fore, back)
102}
103
104pub fn invert_bw(color: u8) -> u8 {
106 match color {
107 0 | 8 | 16..21 | 52..61 | 88..93 | 232..239 => 231,
108 _ => 16,
109 }
110}
111
112pub fn wrap(color: usize) -> u8 {
114 (if color > 0 { color % 255 } else { color }) as u8
115}
116
117fn io_term_cols() -> std::io::Result<usize> {
126 use std::process::{Command, Stdio};
127 let mut cmd = Command::new("/bin/stty");
128 let cmd = cmd.args(vec!["-a"]);
129 let cmd = cmd.stdin(Stdio::inherit());
130 let cmd = cmd.stdout(Stdio::piped());
131 let cmd = cmd.stderr(Stdio::piped());
132 let child = cmd.spawn()?;
133 let output = child.wait_with_output()?;
134 let lines = String::from_utf8_lossy(&output.stdout)
135 .to_string()
136 .lines()
137 .map(String::from)
138 .collect::<Vec<String>>();
139 let lines = lines[0]
140 .split(';')
141 .map(String::from)
142 .collect::<Vec<String>>();
143 if lines.len() > 2 {
144 let fields = lines[2]
145 .split(' ')
146 .map(String::from)
147 .collect::<Vec<String>>();
148 if let Ok(cols) = usize::from_str_radix(&fields[1], 10) {
149 return Ok(cols);
150 }
151 }
152 Ok(DEFAULT_COLUMNS)
153}
154
155pub fn term_cols() -> usize {
159 io_term_cols().unwrap_or_else(|_| DEFAULT_COLUMNS)
160}