entrust-dialog 0.6.0

Interactive terminal dialogs for entrust
Documentation
use crate::dialog::{Dialog, DialogState};
use crate::input;
use crate::input::InputDialog;
use crate::input::prompt::Prompt;
use crate::input::validator::Validator;
use crate::theme::Theme;
use ratatui::crossterm::event::Event;
use ratatui::prelude::{Color, Span};
use ratatui::{Frame, Viewport};
use std::borrow::Cow;

#[derive(Debug)]
pub struct YesNoDialog {
    inner: InputDialog<'static, 'static>,
}

const ORANGE: Color = Color::Rgb(255, 184, 108);

impl Default for YesNoDialog {
    fn default() -> Self {
        let inner = InputDialog::default()
            .with_prompt(Prompt::inline(Span::styled("[y/N] > ", ORANGE)))
            .with_validator(Validator::new(|vec| {
                let mut string: String = vec.iter().collect();
                string.make_ascii_lowercase();
                if "yes".starts_with(string.as_str()) || "no".starts_with(string.as_str()) {
                    None
                } else {
                    Some("Choose yes or no".into())
                }
            }))
            .with_completions(vec!["yes".into(), "no".into()]);
        YesNoDialog { inner }
    }
}

impl YesNoDialog {
    pub fn with_message<M: Into<Cow<'static, str>>>(mut self, message: M) -> Self {
        let prompt = Prompt::inline(vec![
            Span::styled(message.into(), Color::LightBlue),
            Span::styled(" [y/N] > ", ORANGE),
        ]);
        self.inner = self.inner.with_prompt(prompt);
        self
    }

    pub fn with_theme<T: Into<Cow<'static, Theme>>>(mut self, theme: T) -> Self {
        self.inner = self.inner.with_theme(theme);
        self
    }
}

impl Dialog for YesNoDialog {
    type Update = input::Update;
    type Output = bool;

    fn update_for_event(event: Event) -> Option<Self::Update> {
        InputDialog::update_for_event(event)
    }

    fn perform_update(&mut self, update: Self::Update) -> std::io::Result<()> {
        self.inner.perform_update(update)
    }

    fn state(&self) -> DialogState {
        self.inner.state()
    }

    fn output(self) -> Self::Output {
        let mut string = self.inner.output();
        if string.is_empty() {
            false
        } else {
            string.make_ascii_lowercase();
            "yes".starts_with(string.as_str())
        }
    }

    fn viewport(&self) -> Viewport {
        self.inner.viewport()
    }

    fn draw(&mut self, frame: &mut Frame) {
        self.inner.draw(frame)
    }
}