promkit 0.9.1

A toolkit for building your own interactive command-line tools
Documentation
use std::cell::RefCell;

use promkit_core::crossterm::style::ContentStyle;
use promkit_widgets::{cursor::Cursor, text_editor};

use crate::{
    crossterm::style::{Attribute, Attributes},
    switch::ActiveKeySwitcher,
    Prompt,
};

mod keymap;
mod render;

/// `Form` struct provides functionality for managing multiple text input fields.
pub struct Form {
    keymap: ActiveKeySwitcher<keymap::Keymap>,
    text_editor_states: Vec<text_editor::State>,
    /// Overwrite the default styles of text editor states when unselected.
    overwrite_styles: Vec<render::Style>,
}

impl Form {
    pub fn new<I: IntoIterator<Item = text_editor::State>>(states: I) -> Self {
        let (text_editor_states, overwrite_styles): (Vec<_>, Vec<_>) = states
            .into_iter()
            .map(|state| {
                let style = render::Style {
                    prefix_style: ContentStyle {
                        attributes: Attributes::from(Attribute::Dim),
                        ..state.prefix_style
                    },
                    active_char_style: ContentStyle {
                        attributes: Attributes::from(Attribute::Dim),
                        ..Default::default()
                    },
                    inactive_char_style: ContentStyle {
                        attributes: Attributes::from(Attribute::Dim),
                        ..state.inactive_char_style
                    },
                };
                (state, style)
            })
            .unzip();
        Self {
            keymap: ActiveKeySwitcher::new("default", self::keymap::default as keymap::Keymap),
            text_editor_states,
            overwrite_styles,
        }
    }

    pub fn prompt(self) -> anyhow::Result<Prompt<render::Renderer>> {
        let default_styles = self
            .text_editor_states
            .iter()
            .map(|state| render::Style {
                prefix_style: state.prefix_style,
                active_char_style: state.active_char_style,
                inactive_char_style: state.inactive_char_style,
            })
            .collect();
        let mut renderer = render::Renderer {
            keymap: RefCell::new(self.keymap),
            text_editor_states: Cursor::new(self.text_editor_states, 0, false),
            default_styles,
            overwrite_styles: self.overwrite_styles,
        };
        renderer.overwrite_styles();
        Ok(Prompt { renderer })
    }
}