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
106
107
108
109
110
111
#[cfg(doctest)]
#[macro_use]
extern crate doc_comment;
#[macro_use]
extern crate lazy_static;
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate regex;
#[macro_use]
extern crate syn;
use proc_macro::TokenStream;
use regex::Regex;
use syn::LitStr;
#[proc_macro]
pub fn ansi(tokens: TokenStream) -> TokenStream {
let format_str = parse_macro_input!(tokens as LitStr).value();
lazy_static! {
static ref ANSI_ARG: Regex =
Regex::new(r"\{(?P<format>[:#?A-z0-9\.]*);(?P<color>[\w, ]+)\}").unwrap();
}
let format_str = ANSI_ARG.replace_all(&format_str, |captures: ®ex::Captures| {
let format = captures.name("format").map(|m| m.as_str()).unwrap_or("");
let color = captures.name("color").map(|m| m.as_str());
let format_arg = match color {
None => format!("{{{format}}}", format = format),
Some(options) => {
let options: Vec<_> = options
.split(',')
.map(|option| match option {
"bold" => "1",
"faint" => "2",
"italic" => "3",
"underline" => "4",
"black" => "30",
"red" => "31",
"green" => "32",
"yellow" => "33",
"blue" => "34",
"magenta" => "35",
"cyan" => "36",
"white" => "37",
"bright black" => "90",
"gray" => "90",
"grey" => "90",
"bright red" => "91",
"bright green" => "92",
"bright yellow" => "93",
"bright blue" => "94",
"bright magenta" => "95",
"bright cyan" => "96",
"bright white" => "97",
"on black" => "40",
"on red" => "41",
"on green" => "42",
"on yellow" => "43",
"on blue" => "44",
"on magenta" => "45",
"on cyan" => "46",
"on white" => "47",
"on bright black" => "100",
"on gray" => "100",
"on grey" => "100",
"on bright red" => "101",
"on bright green" => "102",
"on bright yellow" => "103",
"on bright blue" => "104",
"on bright magenta" => "105",
"on bright cyan" => "106",
"on bright white" => "107",
s => unimplemented!("Not supported: {}", s),
})
.collect();
let options: String = options.join(";");
format!(
"\u{001b}[{colors}m{{{format}}}\u{001b}[0m",
colors = options,
format = format,
)
}
};
format_arg
});
let tokens = quote! {
#format_str
};
TokenStream::from(tokens)
}
#[cfg(doctest)]
doctest!("../README.md");