Skip to main content

entrust_dialog/input/
confirmation.rs

1use crate::dialog::DialogState;
2use crate::input::InputDialog;
3use crate::input::prompt::Prompt;
4use crate::input::validator::Validator;
5use std::mem;
6
7#[derive(Debug, Clone)]
8pub struct Confirmation<'c> {
9    prompt: Prompt<'c>,
10    validation_message: &'static str,
11    is_active: bool,
12}
13
14impl<'c> Confirmation<'c> {
15    pub fn new(prompt: Prompt<'c>) -> Self {
16        Confirmation {
17            prompt,
18            validation_message: "no match",
19            is_active: false,
20        }
21    }
22
23    pub fn with_validation_message(mut self, validation_message: &'static str) -> Self {
24        self.validation_message = validation_message;
25        self
26    }
27}
28
29impl<'p, 'c> InputDialog<'p, 'c> {
30    pub(super) fn confirm(&mut self) {
31        match self.confirmation.as_mut() {
32            None => self.state = DialogState::Completed,
33            Some(confirmation) if confirmation.is_active => self.state = DialogState::Completed,
34            Some(confirmation) => {
35                let first = mem::take(&mut self.content);
36                self.cursor.set_index(0);
37                let message = confirmation.validation_message;
38                self.validator = Validator::new(move |chars| {
39                    if chars == first {
40                        None
41                    } else {
42                        Some(message.into())
43                    }
44                });
45                confirmation.is_active = true;
46            }
47        }
48    }
49
50    pub(super) fn prompt_with_confirmation(&self) -> Prompt<'_> {
51        self.confirmation
52            .as_ref()
53            .and_then(|c| {
54                if c.is_active {
55                    Some(c.prompt.clone())
56                } else {
57                    None
58                }
59            })
60            .unwrap_or(self.prompt.clone())
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use crate::dialog::Dialog;
68    use crate::input::Update;
69    use crate::input::prompt::Prompt;
70    use ratatui::prelude::Line;
71
72    #[test]
73    fn test() {
74        let prompt_header = "header prompt";
75        let prompt_inline = "inline prompt";
76        let confirmation_header = "repeat";
77        let validation_message = "no match";
78        let mut dialog = InputDialog::default()
79            .with_prompt(Prompt::new(prompt_header, prompt_inline))
80            .with_confirmation(
81                Confirmation::new(Prompt::header(confirmation_header))
82                    .with_validation_message(validation_message),
83            );
84
85        dialog.perform_update(Update::InsertChar('a')).unwrap();
86        assert!(!dialog.confirmation.as_ref().unwrap().is_active);
87        assert_eq!(
88            Line::raw(prompt_header),
89            dialog.prompt_with_confirmation().header
90        );
91
92        dialog.perform_update(Update::Confirm).unwrap();
93        assert!(dialog.content.is_empty());
94        assert!(dialog.confirmation.as_ref().unwrap().is_active);
95        assert_eq!(
96            Line::raw(confirmation_header),
97            dialog.prompt_with_confirmation().header
98        );
99
100        dialog.perform_update(Update::InsertChar('b')).unwrap();
101        dialog.perform_update(Update::Confirm).unwrap();
102        assert_eq!(Some(validation_message.into()), dialog.validation_message());
103        assert_eq!(DialogState::Pending, dialog.state);
104
105        dialog.perform_update(Update::DeleteBeforeCursor).unwrap();
106        dialog.perform_update(Update::InsertChar('a')).unwrap();
107        assert_eq!(None, dialog.validation_message());
108        dialog.perform_update(Update::Confirm).unwrap();
109        assert_eq!(DialogState::Completed, dialog.state);
110    }
111}