Skip to main content

inquire/ui/api/
render_config.rs

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