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}