inquire/ui/api/
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<'a> {
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<&'a 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<&'a 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<&'a str>,
83
84    /// Render configuration for error messages.
85    pub error_message: ErrorMessageRenderConfig<'a>,
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<&'a 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<&'a 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<&'a 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<&'a 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<&'a 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<'a>,
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<'a> RenderConfig<'a> {
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<&'a str>) -> Self {
216        self.prompt_prefix = prompt_prefix;
217        self
218    }
219
220    /// Sets the answered prompt prefix and its style sheet.
221    pub fn with_answered_prompt_prefix(mut self, answered_prompt_prefix: Styled<&'a str>) -> Self {
222        self.answered_prompt_prefix = answered_prompt_prefix;
223        self
224    }
225
226    /// Sets style for text inputs.
227    pub fn with_text_input(mut self, text_input: StyleSheet) -> Self {
228        self.text_input = text_input;
229        self
230    }
231
232    /// Sets the style sheet for default values.
233    pub fn with_default_value(mut self, default_value: StyleSheet) -> Self {
234        self.default_value = default_value;
235        self
236    }
237
238    /// Sets the style sheet for help messages.
239    pub fn with_help_message(mut self, help_message: StyleSheet) -> Self {
240        self.help_message = help_message;
241        self
242    }
243
244    /// Sets the style sheet for answers.
245    pub fn with_answer(mut self, answer: StyleSheet) -> Self {
246        self.answer = answer;
247        self
248    }
249
250    /// Sets the render configuration for error messages.
251    pub fn with_error_message(mut self, error_message: ErrorMessageRenderConfig<'a>) -> Self {
252        self.error_message = error_message;
253        self
254    }
255
256    /// Sets the styled component for prefixes in highlighted options.
257    pub fn with_highlighted_option_prefix(
258        mut self,
259        highlighted_option_prefix: Styled<&'a str>,
260    ) -> Self {
261        self.highlighted_option_prefix = highlighted_option_prefix;
262        self
263    }
264
265    /// Sets the styled component for prefixes in scroll-up indicators.
266    pub fn with_scroll_up_prefix(mut self, scroll_up_prefix: Styled<&'a str>) -> Self {
267        self.scroll_up_prefix = scroll_up_prefix;
268        self
269    }
270
271    /// Sets the styled component for prefixes in scroll-down indicators.
272    pub fn with_scroll_down_prefix(mut self, scroll_down_prefix: Styled<&'a str>) -> Self {
273        self.scroll_down_prefix = scroll_down_prefix;
274        self
275    }
276
277    /// Sets the styled component for selected checkboxes.
278    pub fn with_selected_checkbox(mut self, selected_checkbox: Styled<&'a str>) -> Self {
279        self.selected_checkbox = selected_checkbox;
280        self
281    }
282
283    /// Sets the styled component for unselected checkboxes.
284    pub fn with_unselected_checkbox(mut self, unselected_checkbox: Styled<&'a str>) -> Self {
285        self.unselected_checkbox = unselected_checkbox;
286        self
287    }
288
289    /// Sets the index prefix for option lists.
290    pub fn with_option_index_prefix(mut self, index_prefix: IndexPrefix) -> Self {
291        self.option_index_prefix = index_prefix;
292        self
293    }
294
295    /// Sets the style sheet for option values.
296    pub fn with_option(mut self, option: StyleSheet) -> Self {
297        self.option = option;
298        self
299    }
300
301    /// Sets the style sheet for currently selected option.
302    pub fn with_selected_option(mut self, selected_option: Option<StyleSheet>) -> Self {
303        self.selected_option = selected_option;
304        self
305    }
306
307    /// Sets the indicator for canceled prompts.
308    pub fn with_canceled_prompt_indicator(
309        mut self,
310        canceled_prompt_indicator: Styled<&'a str>,
311    ) -> Self {
312        self.canceled_prompt_indicator = canceled_prompt_indicator;
313        self
314    }
315
316    #[cfg(feature = "date")]
317    /// Sets the render configuration for calendars.
318    pub fn with_calendar_config(mut self, calendar: calendar::CalendarRenderConfig<'a>) -> Self {
319        self.calendar = calendar;
320        self
321    }
322
323    #[cfg(feature = "editor")]
324    /// Sets the render configuration for editor prompts.
325    pub fn with_editor_prompt(mut self, editor_prompt: StyleSheet) -> Self {
326        self.editor_prompt = editor_prompt;
327        self
328    }
329}
330
331impl<'a> Default for RenderConfig<'a> {
332    fn default() -> Self {
333        match env::var("NO_COLOR") {
334            Ok(_) => Self::empty(),
335            Err(_) => Self::default_colored(),
336        }
337    }
338}
339
340/// Definition of index prefixes in option lists.
341#[derive(Copy, Clone, Debug, PartialEq, Eq)]
342pub enum IndexPrefix {
343    /// Lists of options will not display any hints regarding
344    /// the position/index of the positions.
345    None,
346
347    /// A simple index (1-based) will be displayed before the
348    /// option string representation.
349    Simple,
350
351    /// A simple index (1-based) will be displayed before the
352    /// option string representation.
353    ///
354    /// The number representation of the index is padded with
355    /// spaces so that the length is the same of the largest
356    /// index. That is, if the list has 100 options, the first 9
357    /// options will be rendered as `"  1", "  2", ...`. Then all
358    /// indexes with two digits will be padded with one space, and
359    /// finally the last option with index 100 will not need to be
360    /// padded.
361    SpacePadded,
362
363    /// A simple index (1-based) will be displayed before the
364    /// option string representation.
365    ///
366    /// The number representation of the index is padded with
367    /// zeroes so that the length is the same of the largest
368    /// index. That is, if the list has 100 options, the first 9
369    /// options will be rendered as `"001", "002", ...`. Then all
370    /// indexes with two digits will be padded with one zero, and
371    /// finally the last option with index 100 will not need to be
372    /// padded.
373    ZeroPadded,
374}
375
376/// Render configuration for error messages.
377#[derive(Copy, Clone, Debug)]
378pub struct ErrorMessageRenderConfig<'a> {
379    /// Prefix style.
380    pub prefix: Styled<&'a str>,
381
382    /// Separator style.
383    ///
384    /// Note: This separator is a space character. It might be useful to
385    /// style it if you want to set a background color for error messages.
386    pub separator: StyleSheet,
387
388    /// Message style.
389    pub message: StyleSheet,
390
391    /// Default message used for validators that do not defined custom error messages.
392    pub default_message: &'a str,
393}
394
395impl<'a> ErrorMessageRenderConfig<'a> {
396    /// Render configuration in which no colors or attributes are applied.
397    pub fn empty() -> Self {
398        Self {
399            prefix: Styled::new("#"),
400            separator: StyleSheet::empty(),
401            message: StyleSheet::empty(),
402            default_message: "Invalid input.",
403        }
404    }
405
406    /// Render configuration where default colors and attributes are applied.
407    pub fn default_colored() -> Self {
408        Self {
409            prefix: Styled::new("#").with_fg(Color::LightRed),
410            separator: StyleSheet::empty(),
411            message: StyleSheet::empty().with_fg(Color::LightRed),
412            default_message: "Invalid input.",
413        }
414    }
415
416    /// Sets the prefix.
417    pub fn with_prefix(mut self, prefix: Styled<&'a str>) -> Self {
418        self.prefix = prefix;
419        self
420    }
421
422    /// Sets the separator stylesheet.
423    ///
424    /// Note: This separator is a space character. It might be useful to
425    /// style it if you want to set a background color for error messages.
426    pub fn with_separator(mut self, separator: StyleSheet) -> Self {
427        self.separator = separator;
428        self
429    }
430
431    /// Sets the message stylesheet.
432    pub fn with_message(mut self, message: StyleSheet) -> Self {
433        self.message = message;
434        self
435    }
436}
437
438#[cfg(feature = "date")]
439pub mod calendar {
440    //! Module containing additional render config for date prompts.
441
442    use super::{Color, StyleSheet, Styled};
443
444    /// Calendar configuration for error messages.
445    #[derive(Copy, Clone, Debug)]
446    pub struct CalendarRenderConfig<'a> {
447        /// Prefix style.
448        pub prefix: Styled<&'a str>,
449
450        /// Style sheet for the calendar header, e.g. january 2021.
451        pub header: StyleSheet,
452
453        /// Style sheet for the calendar week header, e.g. su mo tu we th fr sa.
454        pub week_header: StyleSheet,
455
456        /// Style sheet for the currently selected date.
457        ///
458        /// When `None`, no custom style sheet will be applied and the native
459        /// terminal cursor will be used in the first char of the date number.
460        ///
461        /// When `Some(_)`, the style sheet will be applied to the two columns
462        /// where the number is positioned, padded to spaces in the left if the
463        /// number only has one digit. e.g. " 5" or "23".
464        pub selected_date: Option<StyleSheet>,
465
466        /// Style sheet for today's date, just for hinting purposes.
467        pub today_date: StyleSheet,
468
469        /// Style sheet for dates that are from the previous or next month
470        /// displayed in the calendar.
471        pub different_month_date: StyleSheet,
472
473        /// Style sheet for dates that can not be selected due to the
474        /// min/max settings.
475        pub unavailable_date: StyleSheet,
476    }
477
478    impl<'a> CalendarRenderConfig<'a> {
479        /// Render configuration in which no colors or attributes are applied.
480        pub fn empty() -> Self {
481            Self {
482                prefix: Styled::new(">"),
483                header: StyleSheet::empty(),
484                week_header: StyleSheet::empty(),
485                selected_date: None,
486                today_date: StyleSheet::empty(),
487                different_month_date: StyleSheet::empty(),
488                unavailable_date: StyleSheet::empty(),
489            }
490        }
491
492        /// Render configuration where default colors and attributes are applied.
493        pub fn default_colored() -> Self {
494            Self {
495                prefix: Styled::new(">").with_fg(Color::LightGreen),
496                header: StyleSheet::empty(),
497                week_header: StyleSheet::empty(),
498                selected_date: Some(
499                    StyleSheet::empty()
500                        .with_fg(Color::Black)
501                        .with_bg(Color::Grey),
502                ),
503                today_date: StyleSheet::empty().with_fg(Color::LightGreen),
504                different_month_date: StyleSheet::empty().with_fg(Color::DarkGrey),
505                unavailable_date: StyleSheet::empty().with_fg(Color::DarkGrey),
506            }
507        }
508
509        /// Sets the prefix.
510        pub fn with_prefix(mut self, prefix: Styled<&'a str>) -> Self {
511            self.prefix = prefix;
512            self
513        }
514    }
515}