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
93
94
95
96
97
98
99
100
101
102
103
104
105
use proc_macro::TokenStream;
use quote::quote;
use regex::Regex;
#[proc_macro]
pub fn parse_logos(_input: TokenStream) -> TokenStream {
let raw_logos = include_str!("../logos.sh");
let raw_logos = raw_logos
.split_once("in\n")
.expect("Invalid logos.sh file")
.1;
let raw_logos = raw_logos
.split_once("\nesac")
.expect("Invalid logos.sh file")
.0;
let mut tux = None;
let logos = raw_logos
.split(";;\n")
.filter_map(|raw_logo| {
let (is_tux, logo) = parse_logo(raw_logo)?;
if is_tux {
tux = Some(logo.clone());
}
Some(logo)
})
.collect::<Vec<_>>();
let tux = tux.unwrap();
quote! { (#tux, [#(#logos),*]) }.into()
}
fn parse_logo(input: &str) -> Option<(bool, proc_macro2::TokenStream)> {
let input = input.trim().replace('\t', "");
if input.is_empty() {
return None;
}
let regex = Regex::new(r"^\(?(.*)\)[\s\S]*read_ascii *(\d)? *(\d)?").unwrap();
let groups = regex
.captures(&input)
.expect("Error while parsing logos.sh");
let pattern = &groups[1];
let primary_color = match groups.get(2) {
Some(color) => color.as_str().parse::<u8>().unwrap(),
None => 7,
};
let secondary_color = match groups.get(3) {
Some(color) => color.as_str().parse::<u8>().unwrap(),
None => (primary_color + 1) % 8,
};
let logo = input
.split_once("EOF\n")
.expect("Could not find start of logo")
.1
.split_once("\nEOF")
.expect("Could not find end of logo")
.0;
let mut logo_parts = vec![];
for logo_part in logo.split("${") {
if let Some((new_color, rest)) = logo_part.split_once('}') {
let new_color: u8 = match new_color {
"c0" => 0,
"c1" => 1,
"c2" => 2,
"c3" => 3,
"c4" => 4,
"c5" => 5,
"c6" => 6,
"c7" => 7,
_ => panic!("Unknown color: {new_color}"),
};
let rest = rest.replace("\\\\", "\\");
let rest = rest.replace("\\`", "`");
let lines = rest.split('\n').collect::<Vec<_>>();
let last_index = lines.len() - 1;
for (index, line) in lines.into_iter().enumerate() {
let mut line = line.to_owned();
if index != last_index {
line += "\n";
}
logo_parts.push(quote! { (Color(#new_color), #line) });
}
} else if !logo_part.is_empty() {
let logo_part = logo_part.replace("\\\\", "\\");
logo_parts.push(quote! { (Color(9), #logo_part) });
}
}
Some((
pattern == "[Ll]inux*",
quote! {
Logo {
primary_color: Color(#primary_color),
secondary_color: Color(#secondary_color),
pattern: #pattern,
logo_parts: &[#(#logo_parts),*],
}
},
))
}