clap_builder/builder/
styling.rs

1//! Terminal [`Styles`] for help and error output
2
3pub use anstyle::*;
4
5/// Terminal styling definitions
6///
7/// See also [`Command::styles`][crate::Command::styles].
8///
9/// # Example
10///
11/// clap v3 styling
12/// ```rust
13/// # use clap_builder as clap;
14/// # use clap::builder::styling::*;
15/// let styles = Styles::styled()
16///     .header(AnsiColor::Yellow.on_default())
17///     .usage(AnsiColor::Green.on_default())
18///     .literal(AnsiColor::Green.on_default())
19///     .placeholder(AnsiColor::Green.on_default());
20/// ```
21#[derive(Clone, Debug)]
22#[allow(missing_copy_implementations)] // Large enough type that I want an explicit `clone()` for now
23pub struct Styles {
24    header: Style,
25    error: Style,
26    usage: Style,
27    literal: Style,
28    placeholder: Style,
29    valid: Style,
30    invalid: Style,
31    context: Style,
32    context_value: Option<Style>,
33}
34
35impl Styles {
36    /// No terminal styling
37    pub const fn plain() -> Self {
38        Self {
39            header: Style::new(),
40            error: Style::new(),
41            usage: Style::new(),
42            literal: Style::new(),
43            placeholder: Style::new(),
44            valid: Style::new(),
45            invalid: Style::new(),
46            context: Style::new(),
47            context_value: None,
48        }
49    }
50
51    /// Default terminal styling
52    pub const fn styled() -> Self {
53        #[cfg(feature = "color")]
54        {
55            Self {
56                header: Style::new().bold().underline(),
57                error: Style::new()
58                    .fg_color(Some(Color::Ansi(AnsiColor::Red)))
59                    .bold(),
60                usage: Style::new().bold().underline(),
61                literal: Style::new().bold(),
62                placeholder: Style::new(),
63                valid: Style::new().fg_color(Some(Color::Ansi(AnsiColor::Green))),
64                invalid: Style::new().fg_color(Some(Color::Ansi(AnsiColor::Yellow))),
65                context: Style::new(),
66                context_value: None,
67            }
68        }
69        #[cfg(not(feature = "color"))]
70        {
71            Self::plain()
72        }
73    }
74
75    /// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
76    #[inline]
77    pub const fn header(mut self, style: Style) -> Self {
78        self.header = style;
79        self
80    }
81
82    /// Error heading
83    #[inline]
84    pub const fn error(mut self, style: Style) -> Self {
85        self.error = style;
86        self
87    }
88
89    /// Usage heading
90    #[inline]
91    pub const fn usage(mut self, style: Style) -> Self {
92        self.usage = style;
93        self
94    }
95
96    /// Literal command-line syntax, e.g. `--help`
97    #[inline]
98    pub const fn literal(mut self, style: Style) -> Self {
99        self.literal = style;
100        self
101    }
102
103    /// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name]
104    #[inline]
105    pub const fn placeholder(mut self, style: Style) -> Self {
106        self.placeholder = style;
107        self
108    }
109
110    /// Highlight suggested usage
111    #[inline]
112    pub const fn valid(mut self, style: Style) -> Self {
113        self.valid = style;
114        self
115    }
116
117    /// Highlight invalid usage
118    #[inline]
119    pub const fn invalid(mut self, style: Style) -> Self {
120        self.invalid = style;
121        self
122    }
123
124    /// Highlight all specified contexts, e.g. `[default: false]`
125    ///
126    /// To specialize the style of the value within the context, see [`Styles::context_value`]
127    #[inline]
128    pub const fn context(mut self, style: Style) -> Self {
129        self.context = style;
130        self
131    }
132
133    /// Highlight values within all of the context, e.g. the `false` in `[default: false]`
134    ///
135    /// If not explicitly set, falls back to `context`'s style.
136    #[inline]
137    pub const fn context_value(mut self, style: Style) -> Self {
138        self.context_value = Some(style);
139        self
140    }
141}
142
143/// Reflection
144impl Styles {
145    /// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
146    #[inline(always)]
147    pub const fn get_header(&self) -> &Style {
148        &self.header
149    }
150
151    /// Error heading
152    #[inline(always)]
153    pub const fn get_error(&self) -> &Style {
154        &self.error
155    }
156
157    /// Usage heading
158    #[inline(always)]
159    pub const fn get_usage(&self) -> &Style {
160        &self.usage
161    }
162
163    /// Literal command-line syntax, e.g. `--help`
164    #[inline(always)]
165    pub const fn get_literal(&self) -> &Style {
166        &self.literal
167    }
168
169    /// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name]
170    #[inline(always)]
171    pub const fn get_placeholder(&self) -> &Style {
172        &self.placeholder
173    }
174
175    /// Highlight suggested usage
176    #[inline(always)]
177    pub const fn get_valid(&self) -> &Style {
178        &self.valid
179    }
180
181    /// Highlight invalid usage
182    #[inline(always)]
183    pub const fn get_invalid(&self) -> &Style {
184        &self.invalid
185    }
186
187    /// Highlight all specified contexts, e.g. `[default: false]`
188    ///
189    /// To specialize the style of the value within the context, see [`Styles::context_value`]
190    #[inline(always)]
191    pub const fn get_context(&self) -> &Style {
192        &self.context
193    }
194
195    /// Highlight values within all of the context, e.g. the `false` in `[default: false]`
196    ///
197    /// If not explicitly set, falls back to `context`'s style.
198    #[inline(always)]
199    pub const fn get_context_value(&self) -> &Style {
200        match &self.context_value {
201            Some(s) => s,
202            None => &self.context,
203        }
204    }
205}
206
207impl super::AppExt for Styles {}
208
209impl Default for Styles {
210    fn default() -> Self {
211        Self::styled()
212    }
213}
214
215impl Default for &'_ Styles {
216    fn default() -> Self {
217        const STYLES: Styles = Styles::styled();
218        &STYLES
219    }
220}