//! ref: composer/src/Composer/Console/HtmlOutputFormatter.php use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; use shirabe_external_packages::symfony::console::formatter::OutputFormatter; use shirabe_external_packages::symfony::console::formatter::OutputFormatterInterface; use shirabe_external_packages::symfony::console::formatter::OutputFormatterStyleInterface; #[derive(Debug)] pub struct HtmlOutputFormatter { inner: OutputFormatter, } impl HtmlOutputFormatter { const AVAILABLE_FOREGROUND_COLORS: &'static [(i64, &'static str)] = &[ (30, "black"), (31, "red"), (32, "green"), (33, "yellow"), (34, "blue"), (35, "magenta"), (36, "cyan"), (37, "white"), ]; const AVAILABLE_BACKGROUND_COLORS: &'static [(i64, &'static str)] = &[ (40, "black"), (41, "red"), (42, "green"), (43, "yellow"), (44, "blue"), (45, "magenta"), (46, "cyan"), (47, "white"), ]; const AVAILABLE_OPTIONS: &'static [(i64, &'static str)] = &[ (1, "bold"), (4, "underscore"), //5 => "blink", //7 => "reverse", //8 => "conceal" ]; pub fn new(styles: IndexMap>) -> Self { Self { inner: OutputFormatter::new(true, styles), } } pub fn format(&mut self, message: Option<&str>) -> anyhow::Result> { let formatted = self.inner.format(message)?; let formatted = match formatted { Some(formatted) => formatted, None => return Ok(None), }; let clear_escape_codes = "(?:39|49|0|22|24|25|27|28)"; // Regex pattern compatibility: // The PHP pattern writes the ESC byte as the octal escape `\033`; the `regex` crate reads // `\0` as a backreference, so spell ESC as `\x1b` instead. let pattern = format!( "{{\\x1b\\[([0-9;]+)m(.*?)\\x1b\\[(?:{};)*?{}m}}s", clear_escape_codes, clear_escape_codes ); Ok(Some(Preg::replace_callback( &pattern, |matches| self.format_html(matches), &formatted, ))) } fn format_html(&self, matches: &IndexMap) -> String { let codes_str = matches .get(&CaptureKey::ByIndex(1)) .map(|s| s.as_str()) .unwrap_or(""); let content = matches .get(&CaptureKey::ByIndex(2)) .map(|s| s.as_str()) .unwrap_or(""); let mut out = String::from(" out.push_str("font-weight:bold;"), "underscore" => out.push_str("text-decoration:underline;"), _ => {} } } } format!("{}\">{}", out, content) } }