232 lines
8.8 KiB
Rust
Raw Normal View History

2025-06-27 02:31:23 +01:00
//! From https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
use std::slice::Iter;
use crate::warn;
use crate::ansi_to_image::color::{Color, ColorType};
#[derive(Debug)]
pub(super) enum EscapeSequence {
Reset,
BlackLetterFont,
Bold,
Faint,
Italic,
RapidBlink,
SlowBlink,
Underline,
NotBold,
NotUnderline,
NormalIntensity,
NotItalicNorBlackLetter,
NotBlinking,
ReverseVideo,
Conceal,
CrossedOut,
DefaultForegroundColor,
DefaultBackgroundColor,
PrimaryFont,
SetAlternativeFont,
ForegroundColor(ColorType),
BackgroundColor(ColorType),
DisableProportionalSpacing,
NeitherSuperscriptNorSubscript,
NotReserved,
Unimplemented(Vec<u16>),
Ignore,
}
impl EscapeSequence {
pub(super) fn parse_params(params: Vec<&u16>) -> Vec<EscapeSequence> {
let iter = &mut params.iter();
let mut result = vec![];
while iter.len() > 0 {
result.push(Self::consume_and_parse(iter))
}
result
}
fn consume_and_parse(iter: &mut Iter<&u16>) -> Self {
if let Some(current) = iter.next() {
return match *current {
0 => Self::Reset,
1 => Self::Bold,
2 => Self::Faint,
3 => Self::Italic,
4 => Self::Underline,
5 => Self::SlowBlink,
6 => Self::RapidBlink,
7 => Self::ReverseVideo,
8 => Self::Conceal,
9 => Self::CrossedOut,
10 => Self::PrimaryFont,
11 => Self::SetAlternativeFont,
12 => Self::SetAlternativeFont,
13 => Self::SetAlternativeFont,
14 => Self::SetAlternativeFont,
15 => Self::SetAlternativeFont,
16 => Self::SetAlternativeFont,
17 => Self::SetAlternativeFont,
18 => Self::SetAlternativeFont,
19 => Self::SetAlternativeFont,
20 => Self::BlackLetterFont,
21 => Self::NotBold,
22 => Self::NormalIntensity,
23 => Self::NotItalicNorBlackLetter,
24 => Self::NotUnderline,
25 => Self::NotBlinking,
26 => Self::Ignore, // Proportional spacing
27 => Self::NotReserved,
28 => Self::Ignore, // Reveal
29 => Self::Ignore, // Not crossed out
30 => Self::ForegroundColor(ColorType::Normal(Color::Black)),
31 => Self::ForegroundColor(ColorType::Normal(Color::Red)),
32 => Self::ForegroundColor(ColorType::Normal(Color::Green)),
33 => Self::ForegroundColor(ColorType::Normal(Color::Yellow)),
34 => Self::ForegroundColor(ColorType::Normal(Color::Blue)),
35 => Self::ForegroundColor(ColorType::Normal(Color::Magenta)),
36 => Self::ForegroundColor(ColorType::Normal(Color::Cyan)),
37 => Self::ForegroundColor(ColorType::Normal(Color::White)),
38 => match iter.next() {
Some(mode) => Self::ForegroundColor(parse_color(mode, iter)),
None => {
warn!(
"[SEQUENCE_PARSER] foreground color mode is not supplied, parse_color(null, ...)",
);
Self::Ignore
}
},
39 => Self::DefaultForegroundColor,
40 => Self::BackgroundColor(ColorType::Normal(Color::Black)),
41 => Self::BackgroundColor(ColorType::Normal(Color::Red)),
42 => Self::BackgroundColor(ColorType::Normal(Color::Green)),
43 => Self::BackgroundColor(ColorType::Normal(Color::Yellow)),
44 => Self::BackgroundColor(ColorType::Normal(Color::Blue)),
45 => Self::BackgroundColor(ColorType::Normal(Color::Magenta)),
46 => Self::BackgroundColor(ColorType::Normal(Color::Cyan)),
47 => Self::BackgroundColor(ColorType::Normal(Color::White)),
48 => match iter.next() {
Some(mode) => Self::BackgroundColor(parse_color(mode, iter)),
None => {
warn!(
"[SEQUENCE_PARSER] background color mode is not supplied, parse_color(null, ...)",
);
Self::Ignore
}
},
49 => Self::DefaultBackgroundColor,
50 => Self::DisableProportionalSpacing,
53 => Self::CrossedOut,
75 => Self::NeitherSuperscriptNorSubscript,
90 => Self::ForegroundColor(ColorType::Bright(Color::Black)),
91 => Self::ForegroundColor(ColorType::Bright(Color::Red)),
92 => Self::ForegroundColor(ColorType::Bright(Color::Green)),
93 => Self::ForegroundColor(ColorType::Bright(Color::Yellow)),
94 => Self::ForegroundColor(ColorType::Bright(Color::Blue)),
95 => Self::ForegroundColor(ColorType::Bright(Color::Magenta)),
96 => Self::ForegroundColor(ColorType::Bright(Color::Cyan)),
97 => Self::ForegroundColor(ColorType::Bright(Color::White)),
100 => Self::BackgroundColor(ColorType::Bright(Color::Black)),
101 => Self::BackgroundColor(ColorType::Bright(Color::Red)),
102 => Self::BackgroundColor(ColorType::Bright(Color::Green)),
103 => Self::BackgroundColor(ColorType::Bright(Color::Yellow)),
104 => Self::BackgroundColor(ColorType::Bright(Color::Blue)),
105 => Self::BackgroundColor(ColorType::Bright(Color::Magenta)),
106 => Self::BackgroundColor(ColorType::Bright(Color::Cyan)),
107 => Self::BackgroundColor(ColorType::Bright(Color::White)),
v => Self::Unimplemented(vec![3, *v]),
};
}
Self::Ignore
}
}
fn parse_color(mode: &u16, iter: &mut Iter<&u16>) -> ColorType {
match mode {
5 => {
let color = iter.next();
if let Some(color) = color {
let color = match color {
0 => ColorType::Normal(Color::Black),
1 => ColorType::Normal(Color::Red),
2 => ColorType::Normal(Color::Green),
3 => ColorType::Normal(Color::Yellow),
4 => ColorType::Normal(Color::Blue),
5 => ColorType::Normal(Color::Magenta),
6 => ColorType::Normal(Color::Cyan),
7 => ColorType::Normal(Color::White),
8 => ColorType::Bright(Color::Black),
9 => ColorType::Bright(Color::Red),
10 => ColorType::Bright(Color::Green),
11 => ColorType::Bright(Color::Yellow),
12 => ColorType::Bright(Color::Blue),
13 => ColorType::Bright(Color::Magenta),
14 => ColorType::Bright(Color::Cyan),
15 => ColorType::Bright(Color::White),
// These are fixed colors and could be used like ansi 38;5;numberm or 48;5;numberm
16..=255 => ColorType::Fixed(**color as u8),
v => {
warn!("[COLOR_PARSER] fixed color value out of range, parse_fixed_color(code: {})",v);
return ColorType::PrimaryForeground;
}
};
return color;
} else {
warn!(
"[COLOR_PARSER] fixed color value not supplied, parse_fixed_color(code: null)"
);
return ColorType::PrimaryForeground;
}
}
2 => match (iter.next(), iter.next(), iter.next()) {
(Some(r), Some(g), Some(b)) => {
let color = ColorType::Rgb {
field1: (**r as u8, **g as u8, **b as u8),
};
return color;
}
(r, g, b) => {
warn!(
"[COLOR_PARSER] rgb color value not supplied (correctly), parse_rgb_color({}, {}, {})",
r.map(|i| i.to_string() ).unwrap_or("null".to_string()),
g.map(|i| i.to_string() ).unwrap_or("null".to_string()),
b.map(|i| i.to_string() ).unwrap_or("null".to_string())
);
return ColorType::PrimaryForeground;
}
},
v => {
warn!(
"[COLOR_PARSER] color mode is not supplied correctly, parse_color({}, ...)",
v
);
return ColorType::PrimaryForeground;
}
}
}