inquire/ui/
render_config.rs

1use std::env;
2
3use super::{Color, StyleSheet, Styled};
4
5/// Rendering configuration that can be applied to a prompt.
6///
7/// Render configurations can set mostly style sheets for particular
8/// parts of the prompt layout. Additionally, it allows you to set
9/// the content of a few tokens, such as prompt or error message prefixes.
10///
11/// # Example
12///
13/// ```
14/// use inquire::ui::{Color, RenderConfig, Styled};
15///
16/// let empty: RenderConfig = RenderConfig::empty();
17/// let default: RenderConfig = RenderConfig::default();
18///
19/// let prompt_prefix = Styled::new("$").with_fg(Color::DarkRed);
20/// let mine = default.with_prompt_prefix(prompt_prefix);
21/// ```
22#[derive(Copy, Clone, Debug)]
23pub struct RenderConfig {
24    /// Prefix added before prompts.
25    ///
26    /// Note: a space character will be added to separate the prefix
27    /// and the prompt message.
28    pub prompt_prefix: Styled<&'static str>,
29
30    /// Prefix added before answered prompts.
31    ///
32    /// Note: a space character will be added to separate the prefix
33    /// and the prompt message.
34    pub answered_prompt_prefix: Styled<&'static str>,
35
36    /// Style of the prompt message, applicable to all prompt types.
37    pub prompt: StyleSheet,
38
39    /// Render configuration of default values.
40    ///
41    /// Note: default values are displayed wrapped in parenthesis, e.g. (yes).
42    /// Non-styled space characters is added before the default value display
43    /// and after the default value, as separators.
44    pub default_value: StyleSheet,
45
46    /// Render configuration of placeholders.
47    ///
48    /// Note: placeholders are displayed wrapped in parenthesis, e.g. (yes).
49    /// Non-styled space characters is added before the default value display
50    /// and after the default value, as separators.
51    pub placeholder: StyleSheet,
52
53    /// Render configuration of help messages.
54    ///
55    /// Note: help messages are displayed wrapped in brackets, e.g. [Be careful!].
56    pub help_message: StyleSheet,
57
58    /// Character used to mask password text inputs when in mode
59    /// [`Masked`](crate::prompts::PasswordDisplayMode).
60    ///
61    /// Note: Styles for masked text inputs are set in the
62    /// [`text_input`](crate::ui::RenderConfig::text_input) configuration.
63    pub password_mask: char,
64
65    /// Style sheet for text inputs.
66    ///
67    /// Note: a non-styled space character is added before the text input as
68    /// a separator from the prompt message (or default value display).
69    pub text_input: StyleSheet,
70
71    /// Render configuration of final prompt answers (submissions).
72    ///
73    /// Note: a non-styled space character is added before the answer as
74    /// a separator from the prompt message (or default value display).
75    pub answer: StyleSheet,
76
77    /// Render configuration of the message printed in the place of an answer
78    /// when the prompt is canceled by the user - by pressing ESC.
79    ///
80    /// Note: a non-styled space character is added before the indicator as
81    /// a separator from the prompt message.
82    pub canceled_prompt_indicator: Styled<&'static str>,
83
84    /// Render configuration for error messages.
85    pub error_message: ErrorMessageRenderConfig,
86
87    /// Prefix for the current highlighted option.
88    ///
89    /// Note: a space character will be added to separate the prefix
90    /// and the option value or the checkbox.
91    pub highlighted_option_prefix: Styled<&'static str>,
92
93    /// Prefix for the option listed at the top of the page, when it is possible
94    /// to scroll up.
95    ///
96    /// Note: a space character will be added to separate the prefix
97    /// and the option value or the checkbox.
98    pub scroll_up_prefix: Styled<&'static str>,
99
100    /// Prefix for the option listed at the bottom of the page, when it is possible
101    /// to scroll down.
102    ///
103    /// Note: a space character will be added to separate the prefix
104    /// and the option value or the checkbox.
105    pub scroll_down_prefix: Styled<&'static str>,
106
107    /// Selected checkbox in multi-select options.
108    ///
109    /// Note: a space character will be added to separate the checkbox
110    /// from a possible prefix, and to separate the checkbox from the
111    /// option value to the right.
112    pub selected_checkbox: Styled<&'static str>,
113
114    /// Unselected checkbox in multi-select options.
115    ///
116    /// Note: a space character will be added to separate the checkbox
117    /// from a possible prefix, and to separate the checkbox from the
118    /// option value to the right.
119    pub unselected_checkbox: Styled<&'static str>,
120
121    /// Definition of index prefixes in option lists.
122    pub option_index_prefix: IndexPrefix,
123
124    /// Style sheet for options.
125    ///
126    /// Note: a non-styled space character is added before the option value as
127    /// a separator from the prefix.
128    pub option: StyleSheet,
129
130    /// Style sheet for the option that is currently selected. If the value is
131    /// None, it will fall back to `option`.
132    ///
133    /// Note: a non-styled space character is added before the option value as
134    /// a separator from the prefix.
135    pub selected_option: Option<StyleSheet>,
136
137    /// Render configuration for calendar
138
139    #[cfg(feature = "date")]
140    /// Render configuration for date prompts`
141    pub calendar: calendar::CalendarRenderConfig,
142
143    /// Style sheet of the hint in editor prompts.
144    ///
145    /// The hint is formatted as `[(e) to open {}, (enter) to submit]`
146    /// with the editor name.
147    #[cfg(feature = "editor")]
148    pub editor_prompt: StyleSheet,
149}
150
151impl RenderConfig {
152    /// RenderConfig in which no colors or attributes are applied.
153    pub fn empty() -> Self {
154        Self {
155            prompt_prefix: Styled::new("?"),
156            answered_prompt_prefix: Styled::new("?"),
157            prompt: StyleSheet::empty(),
158            default_value: StyleSheet::empty(),
159            placeholder: StyleSheet::empty(),
160            help_message: StyleSheet::empty(),
161            text_input: StyleSheet::empty(),
162            error_message: ErrorMessageRenderConfig::empty(),
163            answer: StyleSheet::empty(),
164            canceled_prompt_indicator: Styled::new("<canceled>"),
165            password_mask: '*',
166            highlighted_option_prefix: Styled::new(">"),
167            scroll_up_prefix: Styled::new("^"),
168            scroll_down_prefix: Styled::new("v"),
169            selected_checkbox: Styled::new("[x]"),
170            unselected_checkbox: Styled::new("[ ]"),
171            option_index_prefix: IndexPrefix::None,
172            option: StyleSheet::empty(),
173            selected_option: None,
174
175            #[cfg(feature = "date")]
176            calendar: calendar::CalendarRenderConfig::empty(),
177
178            #[cfg(feature = "editor")]
179            editor_prompt: StyleSheet::empty(),
180        }
181    }
182
183    /// RenderConfig where default colors and attributes are applied.
184    pub fn default_colored() -> Self {
185        Self {
186            prompt_prefix: Styled::new("?").with_fg(Color::LightGreen),
187            answered_prompt_prefix: Styled::new(">").with_fg(Color::LightGreen),
188            prompt: StyleSheet::empty(),
189            default_value: StyleSheet::empty(),
190            placeholder: StyleSheet::new().with_fg(Color::DarkGrey),
191            help_message: StyleSheet::empty().with_fg(Color::LightCyan),
192            text_input: StyleSheet::empty(),
193            error_message: ErrorMessageRenderConfig::default_colored(),
194            password_mask: '*',
195            answer: StyleSheet::empty().with_fg(Color::LightCyan),
196            canceled_prompt_indicator: Styled::new("<canceled>").with_fg(Color::DarkRed),
197            highlighted_option_prefix: Styled::new(">").with_fg(Color::LightCyan),
198            scroll_up_prefix: Styled::new("^"),
199            scroll_down_prefix: Styled::new("v"),
200            selected_checkbox: Styled::new("[x]").with_fg(Color::LightGreen),
201            unselected_checkbox: Styled::new("[ ]"),
202            option_index_prefix: IndexPrefix::None,
203            option: StyleSheet::empty(),
204            selected_option: Some(StyleSheet::new().with_fg(Color::LightCyan)),
205
206            #[cfg(feature = "date")]
207            calendar: calendar::CalendarRenderConfig::default_colored(),
208
209            #[cfg(feature = "editor")]
210            editor_prompt: StyleSheet::new().with_fg(Color::DarkCyan),
211        }
212    }
213
214    /// Sets the prompt prefix and its style sheet.
215    pub fn with_prompt_prefix(mut self, prompt_prefix: Styled<&'static str>) -> Self {
216        self.prompt_prefix = prompt_prefix;
217        self
218    }
219
220    /// Sets style for text inputs.
221    pub fn with_text_input(mut self, text_input: StyleSheet) -> Self {
222        self.text_input = text_input;
223        self
224    }
225
226    /// Sets the style sheet for default values.
227    pub fn with_default_value(mut self, default_value: StyleSheet) -> Self {
228        self.default_value = default_value;
229        self
230    }
231
232    /// Sets the style sheet for help messages.
233    pub fn with_help_message(mut self, help_message: StyleSheet) -> Self {
234        self.help_message = help_message;
235        self
236    }
237
238    /// Sets the style sheet for answers.
239    pub fn with_answer(mut self, answer: StyleSheet) -> Self {
240        self.answer = answer;
241        self
242    }
243
244    /// Sets the render configuration for error messages.
245    pub fn with_error_message(mut self, error_message: ErrorMessageRenderConfig) -> Self {
246        self.error_message = error_message;
247        self
248    }
249
250    /// Sets the styled component for prefixes in highlighted options.
251    pub fn with_highlighted_option_prefix(
252        mut self,
253        highlighted_option_prefix: Styled<&'static str>,
254    ) -> Self {
255        self.highlighted_option_prefix = highlighted_option_prefix;
256        self
257    }
258
259    /// Sets the styled component for prefixes in scroll-up indicators.
260    pub fn with_scroll_up_prefix(mut self, scroll_up_prefix: Styled<&'static str>) -> Self {
261        self.scroll_up_prefix = scroll_up_prefix;
262        self
263    }
264
265    /// Sets the styled component for prefixes in scroll-down indicators.
266    pub fn with_scroll_down_prefix(mut self, scroll_down_prefix: Styled<&'static str>) -> Self {
267        self.scroll_down_prefix = scroll_down_prefix;
268        self
269    }
270
271    /// Sets the styled component for selected checkboxes.
272    pub fn with_selected_checkbox(mut self, selected_checkbox: Styled<&'static str>) -> Self {
273        self.selected_checkbox = selected_checkbox;
274        self
275    }
276
277    /// Sets the styled component for unselected checkboxes.
278    pub fn with_unselected_checkbox(mut self, unselected_checkbox: Styled<&'static str>) -> Self {
279        self.unselected_checkbox = unselected_checkbox;
280        self
281    }
282
283    /// Sets the index prefix for option lists.
284    pub fn with_option_index_prefix(mut self, index_prefix: IndexPrefix) -> Self {
285        self.option_index_prefix = index_prefix;
286        self
287    }
288
289    /// Sets the style sheet for option values.
290    pub fn with_option(mut self, option: StyleSheet) -> Self {
291        self.option = option;
292        self
293    }
294
295    /// Sets the style sheet for currently selected option.
296    pub fn with_selected_option(mut self, selected_option: Option<StyleSheet>) -> Self {
297        self.selected_option = selected_option;
298        self
299    }
300
301    /// Sets the indicator for canceled prompts.
302    pub fn with_canceled_prompt_indicator(
303        mut self,
304        canceled_prompt_indicator: Styled<&'static str>,
305    ) -> Self {
306        self.canceled_prompt_indicator = canceled_prompt_indicator;
307        self
308    }
309
310    #[cfg(feature = "date")]
311    /// Sets the render configuration for calendars.
312    pub fn with_calendar_config(mut self, calendar: calendar::CalendarRenderConfig) -> Self {
313        self.calendar = calendar;
314        self
315    }
316
317    #[cfg(feature = "editor")]
318    /// Sets the render configuration for editor prompts.
319    pub fn with_editor_prompt(mut self, editor_prompt: StyleSheet) -> Self {
320        self.editor_prompt = editor_prompt;
321        self
322    }
323}
324
325impl Default for RenderConfig {
326    fn default() -> Self {
327        match env::var("NO_COLOR") {
328            Ok(_) => Self::empty(),
329            Err(_) => Self::default_colored(),
330        }
331    }
332}
333
334/// Definition of index prefixes in option lists.
335#[derive(Copy, Clone, Debug, PartialEq, Eq)]
336pub enum IndexPrefix {
337    /// Lists of options will not display any hints regarding
338    /// the position/index of the positions.
339    None,
340
341    /// A simple index (1-based) will be displayed before the
342    /// option string representation.
343    Simple,
344
345    /// A simple index (1-based) will be displayed before the
346    /// option string representation.
347    ///
348    /// The number representation of the index is padded with
349    /// spaces so that the length is the same of the largest
350    /// index. That is, if the list has 100 options, the first 9
351    /// options will be rendered as `"  1", "  2", ...`. Then all
352    /// indexes with two digits will be padded with one space, and
353    /// finally the last option with index 100 will not need to be
354    /// padded.
355    SpacePadded,
356
357    /// A simple index (1-based) will be displayed before the
358    /// option string representation.
359    ///
360    /// The number representation of the index is padded with
361    /// zeroes so that the length is the same of the largest
362    /// index. That is, if the list has 100 options, the first 9
363    /// options will be rendered as `"001", "002", ...`. Then all
364    /// indexes with two digits will be padded with one zero, and
365    /// finally the last option with index 100 will not need to be
366    /// padded.
367    ZeroPadded,
368}
369
370/// Render configuration for error messages.
371#[derive(Copy, Clone, Debug)]
372pub struct ErrorMessageRenderConfig {
373    /// Prefix style.
374    pub prefix: Styled<&'static str>,
375
376    /// Separator style.
377    ///
378    /// Note: This separator is a space character. It might be useful to
379    /// style it if you want to set a background color for error messages.
380    pub separator: StyleSheet,
381
382    /// Message style.
383    pub message: StyleSheet,
384
385    /// Default message used for validators that do not defined custom error messages.
386    pub default_message: &'static str,
387}
388
389impl ErrorMessageRenderConfig {
390    /// Render configuration in which no colors or attributes are applied.
391    pub fn empty() -> Self {
392        Self {
393            prefix: Styled::new("#"),
394            separator: StyleSheet::empty(),
395            message: StyleSheet::empty(),
396            default_message: "Invalid input.",
397        }
398    }
399
400    /// Render configuration where default colors and attributes are applied.
401    pub fn default_colored() -> Self {
402        Self {
403            prefix: Styled::new("#").with_fg(Color::LightRed),
404            separator: StyleSheet::empty(),
405            message: StyleSheet::empty().with_fg(Color::LightRed),
406            default_message: "Invalid input.",
407        }
408    }
409
410    /// Sets the prefix.
411    pub fn with_prefix(mut self, prefix: Styled<&'static str>) -> Self {
412        self.prefix = prefix;
413        self
414    }
415
416    /// Sets the separator stylesheet.
417    ///
418    /// Note: This separator is a space character. It might be useful to
419    /// style it if you want to set a background color for error messages.
420    pub fn with_separator(mut self, separator: StyleSheet) -> Self {
421        self.separator = separator;
422        self
423    }
424
425    /// Sets the message stylesheet.
426    pub fn with_message(mut self, message: StyleSheet) -> Self {
427        self.message = message;
428        self
429    }
430}
431
432#[cfg(feature = "date")]
433pub mod calendar {
434    //! Module containing additional render config for date prompts.
435
436    use super::{Color, StyleSheet, Styled};
437
438    /// Calendar configuration for error messages.
439    #[derive(Copy, Clone, Debug)]
440    pub struct CalendarRenderConfig {
441        /// Prefix style.
442        pub prefix: Styled<&'static str>,
443
444        /// Style sheet for the calendar header, e.g. january 2021.
445        pub header: StyleSheet,
446
447        /// Style sheet for the calendar week header, e.g. su mo tu we th fr sa.
448        pub week_header: StyleSheet,
449
450        /// Style sheet for the currently selected date.
451        ///
452        /// When `None`, no custom style sheet will be applied and the native
453        /// terminal cursor will be used in the first char of the date number.
454        ///
455        /// Whem `Some(_)`, the style sheet will be applied to the two columns
456        /// where the number is positioned, padded to spaces in the left if the
457        /// number only has one digit. e.g. " 5" or "23".
458        pub selected_date: Option<StyleSheet>,
459
460        /// Style sheet for today's date, just for hinting purposes.
461        pub today_date: StyleSheet,
462
463        /// Style sheet for dates that are from the previous or next month
464        /// displayed in the calendar.
465        pub different_month_date: StyleSheet,
466
467        /// Style sheet for dates that can not be selected due to the
468        /// min/max settings.
469        pub unavailable_date: StyleSheet,
470    }
471
472    impl CalendarRenderConfig {
473        /// Render configuration in which no colors or attributes are applied.
474        pub fn empty() -> Self {
475            Self {
476                prefix: Styled::new(">"),
477                header: StyleSheet::empty(),
478                week_header: StyleSheet::empty(),
479                selected_date: None,
480                today_date: StyleSheet::empty(),
481                different_month_date: StyleSheet::empty(),
482                unavailable_date: StyleSheet::empty(),
483            }
484        }
485
486        /// Render configuration where default colors and attributes are applied.
487        pub fn default_colored() -> Self {
488            Self {
489                prefix: Styled::new(">").with_fg(Color::LightGreen),
490                header: StyleSheet::empty(),
491                week_header: StyleSheet::empty(),
492                selected_date: Some(
493                    StyleSheet::empty()
494                        .with_fg(Color::Black)
495                        .with_bg(Color::Grey),
496                ),
497                today_date: StyleSheet::empty().with_fg(Color::LightGreen),
498                different_month_date: StyleSheet::empty().with_fg(Color::DarkGrey),
499                unavailable_date: StyleSheet::empty().with_fg(Color::DarkGrey),
500            }
501        }
502
503        /// Sets the prefix.
504        pub fn with_prefix(mut self, prefix: Styled<&'static str>) -> Self {
505            self.prefix = prefix;
506            self
507        }
508    }
509}