//! 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), Ignore, } impl EscapeSequence { pub(super) fn parse_params(params: Vec<&u16>) -> Vec { 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; } } }