pretty_exec_lib/log/
syntax_highlight.rs1pub use yansi;
2
3use super::{Log, Logger};
4use pipe_trait::Pipe;
5use shell_escape::unix::escape;
6use std::{
7 borrow::Cow,
8 ffi::OsStr,
9 fmt::{self, Display, Formatter},
10};
11use typed_builder::TypedBuilder;
12use yansi::{Color, Style};
13
14#[must_use]
15#[derive(Default, TypedBuilder)]
16pub struct SyntaxHighLight {
17 #[builder(default)]
18 pub prompt: Style,
19 #[builder(default)]
20 pub program: Style,
21 #[builder(default)]
22 pub argument: Style,
23 #[builder(default)]
24 pub short_flag: Style,
25 #[builder(default)]
26 pub long_flag: Style,
27}
28
29impl SyntaxHighLight {
30 pub fn colorless() -> Self {
31 Default::default()
32 }
33
34 pub fn colorful() -> Self {
35 SyntaxHighLight::builder()
36 .prompt(Style::default().dimmed())
37 .program(Style::new(Color::Green))
38 .short_flag(Style::new(Color::Red))
39 .long_flag(Style::new(Color::Red))
40 .build()
41 }
42}
43
44impl<'a, Prompt: ?Sized, Program: ?Sized, Arguments: ?Sized> Display
45 for Logger<'a, SyntaxHighLight, Prompt, Program, Arguments>
46where
47 &'a Prompt: AsRef<str>,
48 &'a Program: AsRef<OsStr>,
49 &'a Arguments: IntoIterator,
50 <&'a Arguments as IntoIterator>::Item: AsRef<OsStr>,
51{
52 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
53 let Logger {
54 method,
55 prompt,
56 program,
57 arguments,
58 } = self;
59
60 let prompt = prompt.as_ref();
61 if !prompt.is_empty() {
62 write!(f, "{} ", method.prompt.paint(prompt))?;
63 }
64
65 let program = program.as_ref().to_string_lossy().pipe(escape);
66 write!(f, "{}", method.program.paint(program))?;
67
68 for argument in *arguments {
69 let argument = argument.as_ref().to_string_lossy();
70 fn paint_escape(text: Cow<str>, style: Style) -> impl Display + '_ {
71 text.pipe(escape).pipe(|text| style.paint(text))
72 }
73 if argument.starts_with("--") {
74 let mut segments = argument.splitn(2, '=');
75 match (segments.next(), segments.next()) {
76 (Some(_), None) => write!(f, " {}", paint_escape(argument, method.long_flag))?,
77 (Some(flag), Some(val)) => write!(
78 f,
79 " {flag}{eq}{val}",
80 flag = paint_escape(flag.into(), method.long_flag),
81 eq = method.argument.paint("="),
82 val = paint_escape(val.into(), method.argument),
83 )?,
84 _ => unreachable!(),
85 }
86 } else if argument.starts_with('-') {
87 write!(f, " {}", paint_escape(argument, method.short_flag))?
88 } else {
89 write!(f, " {}", paint_escape(argument, method.argument))?
90 };
91 }
92
93 Ok(())
94 }
95}
96
97impl<'a, Prompt: ?Sized, Program: ?Sized, Arguments: ?Sized> Log
98 for Logger<'a, SyntaxHighLight, Prompt, Program, Arguments>
99where
100 &'a Prompt: AsRef<str>,
101 &'a Program: AsRef<OsStr>,
102 &'a Arguments: IntoIterator,
103 <&'a Arguments as IntoIterator>::Item: AsRef<OsStr>,
104{
105 fn log(&self) {
106 eprintln!("{self}");
107 }
108}