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}