1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
//! ref: composer/src/Composer/Console/HtmlOutputFormatter.php
use indexmap::IndexMap;
use shirabe_external_packages::composer::pcre::preg::Preg;
use shirabe_external_packages::symfony::console::formatter::output_formatter::OutputFormatter;
use shirabe_external_packages::symfony::console::formatter::output_formatter_style::OutputFormatterStyle;
#[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<String, OutputFormatterStyle>) -> Self {
Self {
inner: OutputFormatter::new(true, styles),
}
}
pub fn format(&self, message: Option<&str>) -> Option<String> {
let formatted = self.inner.format(message)?;
let clear_escape_codes = "(?:39|49|0|22|24|25|27|28)";
let pattern = format!(
"{{\\033\\[([0-9;]+)m(.*?)\\033\\[(?:{};)*?{}m}}s",
clear_escape_codes, clear_escape_codes
);
Preg::replace_callback(&pattern, |matches| self.format_html(matches), formatted).ok()
}
fn format_html(&self, matches: Vec<Option<String>>) -> String {
let codes_str = matches[1].as_deref().unwrap_or("");
let content = matches[2].as_deref().unwrap_or("");
let mut out = String::from("<span style=\"");
for code_str in codes_str.split(';') {
let code: i64 = code_str.parse().unwrap_or(0);
if let Some(&(_, color)) = Self::AVAILABLE_FOREGROUND_COLORS
.iter()
.find(|&&(k, _)| k == code)
{
out.push_str(&format!("color:{};", color));
} else if let Some(&(_, color)) = Self::AVAILABLE_BACKGROUND_COLORS
.iter()
.find(|&&(k, _)| k == code)
{
out.push_str(&format!("background-color:{};", color));
} else if let Some(&(_, option)) =
Self::AVAILABLE_OPTIONS.iter().find(|&&(k, _)| k == code)
{
match option {
"bold" => out.push_str("font-weight:bold;"),
"underscore" => out.push_str("text-decoration:underline;"),
_ => {}
}
}
}
format!("{}\">{}</span>", out, content)
}
}
|