Skip to content

Commit c57f944

Browse files
committed
add a module to enable converting text with ansi escape codes into
colorful text, #checkpoint
1 parent 8b469b0 commit c57f944

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
ansi_escapers = "0.2.0"
910
async-std = { version = "1.12.0", features = ["tokio03", "tokio02", "tokio1"] }
1011
axum = { version = "0.6.20", features = ["tracing", "ws", "macros", "headers"] }
1112
axum-extra = "0.7.7"

src/ansi_to_html.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use ansi_escapers::{interpreter::*, types::*};
2+
3+
// ANSI color constants
4+
const COLOR_BLACK: &str = "#000000";
5+
const COLOR_RED: &str = "#FF0000";
6+
const COLOR_GREEN: &str = "#00FF00";
7+
const COLOR_YELLOW: &str = "#FFFF00";
8+
const COLOR_BLUE: &str = "#0000FF";
9+
const COLOR_MAGENTA: &str = "#FF00FF";
10+
const COLOR_CYAN: &str = "#00FFFF";
11+
const COLOR_WHITE: &str = "#FFFFFF";
12+
const COLOR_BRIGHT_BLACK: &str = "#808080";
13+
const COLOR_BRIGHT_RED: &str = "#FF8080";
14+
const COLOR_BRIGHT_GREEN: &str = "#80FF80";
15+
const COLOR_BRIGHT_YELLOW: &str = "#FFFF80";
16+
const COLOR_BRIGHT_BLUE: &str = "#8080FF";
17+
const COLOR_BRIGHT_MAGENTA: &str = "#FF80FF";
18+
const COLOR_BRIGHT_CYAN: &str = "#80FFFF";
19+
const COLOR_BRIGHT_WHITE: &str = "#FFFFFF";
20+
const COLOR_DEFAULT: &str = "#FFFFFF";
21+
22+
fn get_color_from_code(col: &Color) -> String {
23+
let basic_color_catch = match col {
24+
Color::Black => COLOR_BLACK.to_string(),
25+
Color::Red => COLOR_RED.to_string(),
26+
Color::Green => COLOR_GREEN.to_string(),
27+
Color::Yellow => COLOR_YELLOW.to_string(),
28+
Color::Blue => COLOR_BLUE.to_string(),
29+
Color::Magenta => COLOR_MAGENTA.to_string(),
30+
Color::Cyan => COLOR_CYAN.to_string(),
31+
Color::White => COLOR_WHITE.to_string(),
32+
Color::BrightBlack => COLOR_BRIGHT_BLACK.to_string(),
33+
Color::BrightRed => COLOR_BRIGHT_RED.to_string(),
34+
Color::BrightGreen => COLOR_BRIGHT_GREEN.to_string(),
35+
Color::BrightYellow => COLOR_BRIGHT_YELLOW.to_string(),
36+
Color::BrightBlue => COLOR_BRIGHT_BLUE.to_string(),
37+
Color::BrightMagenta => COLOR_BRIGHT_MAGENTA.to_string(),
38+
Color::BrightCyan => COLOR_BRIGHT_CYAN.to_string(),
39+
Color::BrightWhite => COLOR_BRIGHT_WHITE.to_string(),
40+
Color::Rgb24 { r, g, b } => return format!("#{:02X}{:02X}{:02X}", r, g, b),
41+
Color::AnsiValue(c) => match c {
42+
0..=15 => match c {
43+
0 => COLOR_BLACK.to_string(),
44+
1 => COLOR_RED.to_string(),
45+
2 => COLOR_GREEN.to_string(),
46+
3 => COLOR_YELLOW.to_string(),
47+
4 => COLOR_BLUE.to_string(),
48+
5 => COLOR_MAGENTA.to_string(),
49+
6 => COLOR_CYAN.to_string(),
50+
7 => COLOR_WHITE.to_string(),
51+
8 => COLOR_BRIGHT_BLACK.to_string(),
52+
9 => COLOR_BRIGHT_RED.to_string(),
53+
10 => COLOR_BRIGHT_GREEN.to_string(),
54+
11 => COLOR_BRIGHT_YELLOW.to_string(),
55+
12 => COLOR_BRIGHT_BLUE.to_string(),
56+
13 => COLOR_BRIGHT_MAGENTA.to_string(),
57+
14 => COLOR_BRIGHT_CYAN.to_string(),
58+
15 => COLOR_BRIGHT_WHITE.to_string(),
59+
_ => COLOR_DEFAULT.to_string(),
60+
},
61+
_ => "".to_string(),
62+
},
63+
};
64+
65+
basic_color_catch
66+
}
67+
68+
fn get_html_style(codes: Vec<SgrAttribute>) -> String {
69+
codes
70+
.iter()
71+
.map(|code| -> String {
72+
match code {
73+
SgrAttribute::Background(col) => {
74+
format!("background-color: {};", get_color_from_code(col))
75+
}
76+
SgrAttribute::UnderlineColor(col) => {
77+
format!("text-decoration-color: {};", get_color_from_code(col))
78+
}
79+
SgrAttribute::Foreground(col) => {
80+
format!("color: {};", get_color_from_code(col))
81+
}
82+
SgrAttribute::Bold => "font-weight: bold;".to_string(),
83+
SgrAttribute::Faint => "opacity: 0.7;".to_string(),
84+
SgrAttribute::Italic => "font-style: italic;".to_string(),
85+
SgrAttribute::Underline => "text-decoration: underline;".to_string(),
86+
SgrAttribute::Reverse => "filter: invert(100%);".to_string(),
87+
SgrAttribute::Conceal => "color: transparent;".to_string(),
88+
SgrAttribute::CrossedOut => "text-decoration: line-through;".to_string(),
89+
SgrAttribute::Reset => "".to_string(),
90+
_ => "".to_string(),
91+
}
92+
})
93+
.filter(|s| !s.is_empty())
94+
.collect::<Vec<String>>()
95+
.join(" ")
96+
}
97+
98+
pub fn ansi_to_html(inp: &str) -> String {
99+
let mut interpreter = AnsiParser::new(inp);
100+
let parse_result = interpreter.parse_annotated();
101+
parse_result
102+
.spans
103+
.iter()
104+
.map(|span| -> String {
105+
if span.end > parse_result.text.len() {
106+
return "".to_string();
107+
}
108+
let mut res: String = String::new();
109+
res += format!(
110+
"<span style=\"{}\">{}</span>",
111+
get_html_style(span.codes.clone()),
112+
&parse_result.text[span.start..span.end]
113+
)
114+
.as_str();
115+
116+
res
117+
})
118+
.filter(|x| !x.is_empty())
119+
//.map(|x| x.clone())
120+
.collect::<Vec<String>>()
121+
.join("")
122+
}

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod AppState;
22
mod ControlledProgram;
3+
mod ansi_to_html;
34
mod configuration;
45
mod files;
56
mod macros;

0 commit comments

Comments
 (0)