1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use crossterm::event::{KeyCode, KeyEvent};
use tty_interface::{pos, Interface, Position};
use tty_text::Key;

use crate::{
    dependency::{DependencyId, DependencyState, Evaluation},
    style::drawer_style,
    text::{DrawerContents, Segment, Text},
    Form,
};

use super::{InputResult, Step};

/// A key-value-pair set entry step.
pub struct KeyValueStep {
    prompt: String,
    pairs: Vec<(tty_text::Text, tty_text::Text)>,
    active_pair: usize,
    active_field: usize,
    evaluation: Option<(DependencyId, Evaluation)>,
}

impl KeyValueStep {
    pub fn new(prompt: &str) -> Self {
        Self {
            prompt: prompt.to_string(),
            pairs: vec![(tty_text::Text::new(false), tty_text::Text::new(false))],
            active_pair: 0,
            active_field: 0,
            evaluation: None,
        }
    }

    pub fn set_evaluation(&mut self, evaluation: Evaluation) -> DependencyId {
        let id = DependencyId::new();
        self.evaluation = Some((id, evaluation));
        id
    }
}

impl Step for KeyValueStep {
    fn initialize(&mut self, _dependency_state: &mut DependencyState, _index: usize) {}

    fn render(
        &self,
        interface: &mut Interface,
        _dependency_state: &DependencyState,
        mut position: Position,
        _is_focused: bool,
    ) -> u16 {
        for (pair_index, (key, value)) in self.pairs.iter().enumerate() {
            interface.set(position, &format!("{}: {}", key.value(), value.value()));

            if pair_index == self.active_pair {
                interface.set_cursor(Some(position));
            }

            position = pos!(position.x(), position.y() + 1);
        }

        self.pairs.len() as u16
    }

    fn update(
        &mut self,
        _dependency_state: &mut DependencyState,
        input: KeyEvent,
    ) -> Option<InputResult> {
        let text = if self.active_field == 0 {
            &mut self.pairs[self.active_pair].0
        } else {
            &mut self.pairs[self.active_pair].1
        };

        match input.code {
            KeyCode::Char(ch) => text.handle_input(Key::Char(ch)),
            KeyCode::Backspace => text.handle_input(Key::Backspace),
            KeyCode::Left => text.handle_input(Key::Left),
            KeyCode::Right => text.handle_input(Key::Right),
            _ => {}
        };

        None
    }

    fn help(&self) -> Segment {
        Text::new_styled(self.prompt.to_string(), drawer_style()).as_segment()
    }

    fn drawer(&self) -> Option<DrawerContents> {
        None
    }

    fn result(&self, _dependency_state: &DependencyState) -> String {
        String::new() // TODO
    }

    fn add_to(self, form: &mut Form) {
        form.add_step(Box::new(self));
    }
}