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
pub use yansi;
use super::{Log, Logger};
use pipe_trait::Pipe;
use shell_escape::unix::escape;
use std::{
borrow::Cow,
ffi::OsStr,
fmt::{self, Display, Formatter},
};
use typed_builder::TypedBuilder;
use yansi::{Color, Style};
#[must_use]
#[derive(Default, TypedBuilder)]
pub struct SyntaxHighLight {
#[builder(default)]
pub prompt: Style,
#[builder(default)]
pub program: Style,
#[builder(default)]
pub argument: Style,
#[builder(default)]
pub short_flag: Style,
#[builder(default)]
pub long_flag: Style,
}
impl SyntaxHighLight {
pub fn colorless() -> Self {
Default::default()
}
pub fn colorful() -> Self {
SyntaxHighLight::builder()
.prompt(Style::default().dimmed())
.program(Style::new(Color::Green))
.short_flag(Style::new(Color::Red))
.long_flag(Style::new(Color::Red))
.build()
}
}
impl<'a, Prompt: ?Sized, Program: ?Sized, Arguments: ?Sized> Display
for Logger<'a, SyntaxHighLight, Prompt, Program, Arguments>
where
&'a Prompt: AsRef<str>,
&'a Program: AsRef<OsStr>,
&'a Arguments: IntoIterator,
<&'a Arguments as IntoIterator>::Item: AsRef<OsStr>,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let Logger {
method,
prompt,
program,
arguments,
} = self;
let prompt = prompt.as_ref();
if !prompt.is_empty() {
write!(f, "{} ", method.prompt.paint(prompt))?;
}
let program = program.as_ref().to_string_lossy().pipe(escape);
write!(f, "{}", method.program.paint(program))?;
for argument in *arguments {
let argument = argument.as_ref().to_string_lossy();
fn paint_escape(text: Cow<str>, style: Style) -> impl Display + '_ {
text.pipe(escape).pipe(|text| style.paint(text))
}
if argument.starts_with("--") {
let mut segments = argument.splitn(2, '=');
match (segments.next(), segments.next()) {
(Some(_), None) => write!(f, " {}", paint_escape(argument, method.long_flag))?,
(Some(flag), Some(val)) => write!(
f,
" {flag}{eq}{val}",
flag = paint_escape(flag.into(), method.long_flag),
eq = method.argument.paint("="),
val = paint_escape(val.into(), method.argument),
)?,
_ => unreachable!(),
}
} else if argument.starts_with('-') {
write!(f, " {}", paint_escape(argument, method.short_flag))?
} else {
write!(f, " {}", paint_escape(argument, method.argument))?
};
}
Ok(())
}
}
impl<'a, Prompt: ?Sized, Program: ?Sized, Arguments: ?Sized> Log
for Logger<'a, SyntaxHighLight, Prompt, Program, Arguments>
where
&'a Prompt: AsRef<str>,
&'a Program: AsRef<OsStr>,
&'a Arguments: IntoIterator,
<&'a Arguments as IntoIterator>::Item: AsRef<OsStr>,
{
fn log(&self) {
eprintln!("{self}");
}
}