Skip to main content

tui_kit/wizard/
input.rs

1//! Key-event handling for WizardState.
2
3use crossterm::event::{KeyCode, KeyEvent};
4
5use super::types::{
6    ArrayEditSession, ArrayState, StepKindRef, WizardEvent, WizardState, WizardStep,
7    WizardStepKind,
8};
9use super::helpers::{next_char_boundary, prev_char_boundary, step_kind_at};
10
11impl WizardState {
12    // ── Public constructor / accessors ────────────────────────────────────────
13
14    /// Create a fresh wizard.  `input_count` ≤ total leaf count.
15    pub fn new(steps: &'static [WizardStep], input_count: usize) -> Self {
16        Self {
17            steps, input_count, current: 0,
18            values: Vec::new(), buffer: String::new(), cursor: 0,
19            array_states: std::collections::HashMap::new(), button_selected: 0,
20        }
21    }
22
23    /// Build a pre-completed wizard (edit mode — values already known).
24    pub fn completed(
25        steps: &'static [WizardStep],
26        input_count: usize,
27        values: Vec<String>,
28        start_current: usize,
29    ) -> Self {
30        Self {
31            steps, input_count, current: start_current,
32            values, buffer: String::new(), cursor: 0,
33            array_states: std::collections::HashMap::new(), button_selected: 0,
34        }
35    }
36
37    /// Pre-populate an Array step with existing items (edit mode).
38    pub fn preload_array(&mut self, step_idx: usize, items: Vec<Vec<String>>) {
39        let arr = self.array_states.entry(step_idx).or_insert_with(ArrayState::new);
40        arr.items = items;
41        arr.expanded = true;
42    }
43
44    /// True when all `input_count` steps have been confirmed.
45    pub fn is_complete(&self) -> bool { self.current >= self.input_count }
46
47    /// Set the active leaf index directly (for externally-managed steps).
48    pub fn set_current(&mut self, leaf_idx: usize) { self.current = leaf_idx; }
49
50    /// Borrow the state of an Array step by DFS-leaf index.
51    pub fn array_state(&self, leaf_idx: usize) -> Option<&ArrayState> {
52        self.array_states.get(&leaf_idx)
53    }
54
55    /// Mutably borrow the state of an Array step by DFS-leaf index.
56    pub fn array_state_mut(&mut self, leaf_idx: usize) -> Option<&mut ArrayState> {
57        self.array_states.get_mut(&leaf_idx)
58    }
59
60    /// Return the currently highlighted item index (0-based) for an Array step,
61    /// or `None` if no item is focused (e.g. array is collapsed).
62    pub fn array_selected_item(&self, leaf_idx: usize) -> Option<usize> {
63        self.array_states.get(&leaf_idx).and_then(|a| {
64            if a.expanded && !a.items.is_empty() { Some(a.selected.min(a.items.len().saturating_sub(1))) }
65            else { None }
66        })
67    }
68
69    /// True when the current step is an Array with an active editing session.
70    pub fn is_array_editing(&self) -> bool {
71        matches!(self.current_kind(), Some(StepKindRef::Array(_)))
72            && self.array_states.get(&self.current)
73                   .and_then(|a| a.editing.as_ref()).is_some()
74    }
75
76    // ── Internal helpers ──────────────────────────────────────────────────────
77
78    pub(super) fn current_kind(&self) -> Option<StepKindRef> {
79        step_kind_at(self.steps, self.current, &mut 0)
80    }
81
82    /// If the step we just landed on is an Array, reset it to collapsed / add focused.
83    fn reset_array_on_arrival(&mut self) {
84        if matches!(self.current_kind(), Some(StepKindRef::Array(_))) {
85            if let Some(arr) = self.array_states.get_mut(&self.current) {
86                arr.expanded    = false;
87                arr.selected    = 0;
88                arr.header_sel  = 0;
89                arr.item_btn_sel = 0;
90            }
91        }
92    }
93
94    /// Store `value` at the current leaf index (update-in-place or push).
95    fn commit_value(&mut self, value: String) {
96        if self.current < self.values.len() {
97            self.values[self.current] = value;
98        } else {
99            self.values.push(value);
100        }
101    }
102
103    /// Load the stored value for `leaf_idx` into the buffer, restoring cursor to end.
104    fn load_buffer_for(&mut self, leaf_idx: usize) {
105        self.buffer = self.values.get(leaf_idx).cloned().unwrap_or_default();
106        self.cursor = self.buffer.len();
107    }
108
109    // ── Public key handler ────────────────────────────────────────────────────
110
111    /// Handle a key event. Only meaningful when `!is_complete()`.
112    pub fn handle_key(&mut self, key: KeyEvent) -> WizardEvent {
113        if self.is_complete() { return WizardEvent::None; }
114        let kind = match self.current_kind() {
115            Some(k) => k,
116            None    => return WizardEvent::None,
117        };
118        match kind {
119            StepKindRef::Array(sub_steps) => {
120                let array_idx  = self.current;
121                let is_editing = self.array_states.get(&array_idx)
122                    .and_then(|a| a.editing.as_ref()).is_some();
123                if is_editing {
124                    self.handle_array_edit_key(key, array_idx, sub_steps)
125                } else {
126                    self.handle_array_browse_key(key, array_idx, sub_steps)
127                }
128            }
129            StepKindRef::Leaf | StepKindRef::Optional => self.handle_leaf_key(key),
130            StepKindRef::Select(_) => match key.code {
131                KeyCode::Tab | KeyCode::Enter => {
132                    let index = self.current;
133                    self.commit_value(String::new());
134                    self.current += 1;
135                    if self.is_complete() { WizardEvent::Done(self.values.clone()) }
136                    else { WizardEvent::StepCompleted { index, value: String::new() } }
137                }
138                KeyCode::Esc => WizardEvent::Cancelled,
139                _ => WizardEvent::None,
140            },
141            StepKindRef::Buttons(labels) => self.handle_buttons_key(key, labels),
142        }
143    }
144
145    // ── Leaf step ─────────────────────────────────────────────────────────────
146
147    fn handle_leaf_key(&mut self, key: KeyEvent) -> WizardEvent {
148        match key.code {
149            KeyCode::Char(c) => {
150                self.buffer.insert(self.cursor, c);
151                self.cursor += c.len_utf8();
152                WizardEvent::None
153            }
154            KeyCode::Backspace => {
155                if self.cursor > 0 {
156                    let start = prev_char_boundary(&self.buffer, self.cursor);
157                    let len   = self.cursor - start;
158                    self.buffer.drain(start..self.cursor);
159                    self.cursor -= len;
160                }
161                WizardEvent::None
162            }
163            KeyCode::Delete => {
164                if self.cursor < self.buffer.len() { self.buffer.remove(self.cursor); }
165                WizardEvent::None
166            }
167            KeyCode::Left  => { if self.cursor > 0 { self.cursor = prev_char_boundary(&self.buffer, self.cursor); } WizardEvent::None }
168            KeyCode::Right => { if self.cursor < self.buffer.len() { self.cursor = next_char_boundary(&self.buffer, self.cursor); } WizardEvent::None }
169            KeyCode::Home  => { self.cursor = 0; WizardEvent::None }
170            KeyCode::End   => { self.cursor = self.buffer.len(); WizardEvent::None }
171            KeyCode::Enter | KeyCode::Tab => {
172                let value = std::mem::take(&mut self.buffer);
173                self.cursor = 0;
174                let index = self.current;
175                self.commit_value(value.clone());
176                self.current += 1;
177                if self.is_complete() {
178                    WizardEvent::Done(self.values.clone())
179                } else {
180                    self.load_buffer_for(self.current);
181                    self.reset_array_on_arrival();
182                    WizardEvent::StepCompleted { index, value }
183                }
184            }
185            KeyCode::BackTab => {
186                if self.current > 0 {
187                    self.current -= 1;
188                } else {
189                    self.current = self.input_count.saturating_sub(1);
190                }
191                self.load_buffer_for(self.current);
192                self.reset_array_on_arrival();
193                WizardEvent::None
194            }
195            KeyCode::Esc => WizardEvent::Cancelled,
196            _ => WizardEvent::None,
197        }
198    }
199
200    // ── Buttons step ──────────────────────────────────────────────────────────
201
202    fn handle_buttons_key(&mut self, key: KeyEvent, labels: &'static [&'static str]) -> WizardEvent {
203        match key.code {
204            KeyCode::Left | KeyCode::Char('h') => {
205                if self.button_selected > 0 { self.button_selected -= 1; }
206                WizardEvent::None
207            }
208            KeyCode::BackTab => {
209                if self.button_selected > 0 {
210                    self.button_selected -= 1;
211                } else {
212                    self.button_selected = 0;
213                    self.current = self.current.saturating_sub(1);
214                    self.load_buffer_for(self.current);
215                    self.reset_array_on_arrival();
216                }
217                WizardEvent::None
218            }
219            KeyCode::Right | KeyCode::Char('l') | KeyCode::Tab => {
220                if self.button_selected + 1 < labels.len() {
221                    self.button_selected += 1;
222                } else {
223                    // Wrap forward to the first input step.
224                    self.button_selected = 0;
225                    self.current = 0;
226                    self.load_buffer_for(0);
227                    self.reset_array_on_arrival();
228                }
229                WizardEvent::None
230            }
231            KeyCode::Enter => {
232                let selected = self.button_selected;
233                self.button_selected = 0;
234                if selected == 0 {
235                    self.commit_value(labels[0].to_string());
236                    self.current += 1;
237                    WizardEvent::Done(self.values.clone())
238                } else {
239                    WizardEvent::Cancelled
240                }
241            }
242            KeyCode::Esc => {
243                self.button_selected = 0;
244                WizardEvent::Cancelled
245            }
246            _ => WizardEvent::None,
247        }
248    }
249
250    // ── Array browse (not editing) ────────────────────────────────────────────
251
252    fn handle_array_browse_key(
253        &mut self, key: KeyEvent,
254        array_idx: usize,
255        sub_steps: &'static [WizardStep],
256    ) -> WizardEvent {
257        let expanded   = self.array_states.get(&array_idx).map(|a| a.expanded).unwrap_or(false);
258        let items_len  = self.array_states.get(&array_idx).map(|a| a.items.len()).unwrap_or(0);
259
260        if !expanded {
261            // ── Collapsed: Left/Right change header_sel, Enter expands ──────
262            let header_sel = self.array_states.get(&array_idx).map(|a| a.header_sel).unwrap_or(0);
263            return match key.code {
264                KeyCode::Left => {
265                    if let Some(arr) = self.array_states.get_mut(&array_idx) {
266                        if arr.header_sel > 0 { arr.header_sel -= 1; }
267                    }
268                    WizardEvent::None
269                }
270                KeyCode::Right => {
271                    if let Some(arr) = self.array_states.get_mut(&array_idx) {
272                        if arr.header_sel < 1 { arr.header_sel += 1; }
273                    }
274                    WizardEvent::None
275                }
276                KeyCode::Enter => {
277                    let arr = self.array_states.entry(array_idx).or_insert_with(ArrayState::new);
278                    arr.expanded = true;
279                    arr.header_sel = 0;
280                    if header_sel == 0 {
281                        // [+ add] focused — expand and immediately start adding
282                        let _ = arr; // end borrow before calling helper
283                        self.array_start_add(array_idx, sub_steps)
284                    } else {
285                        // [n] badge focused — just expand
286                        WizardEvent::None
287                    }
288                }
289                KeyCode::Tab  => self.array_advance_wizard(array_idx),
290                KeyCode::BackTab => {
291                    self.array_retreat_wizard();
292                    WizardEvent::None
293                }
294                KeyCode::Esc => WizardEvent::Cancelled,
295                _ => WizardEvent::None,
296            };
297        }
298
299        // ── Expanded: Tab cycles items, Esc collapses ─────────────────────
300        let selected     = self.array_states.get(&array_idx).map(|a| a.selected).unwrap_or(0);
301        let item_btn_sel = self.array_states.get(&array_idx).map(|a| a.item_btn_sel).unwrap_or(0);
302
303        match key.code {
304            KeyCode::Tab => {
305                if items_len > 0 {
306                    if let Some(arr) = self.array_states.get_mut(&array_idx) {
307                        arr.selected = (arr.selected + 1) % items_len;
308                        arr.item_btn_sel = 0;
309                    }
310                }
311                WizardEvent::None
312            }
313            KeyCode::BackTab | KeyCode::Esc => {
314                if let Some(arr) = self.array_states.get_mut(&array_idx) {
315                    arr.expanded     = false;
316                    arr.header_sel   = 0;
317                    arr.item_btn_sel = 0;
318                }
319                WizardEvent::None
320            }
321            // Left/Right navigate inline buttons on the focused item header
322            KeyCode::Left => {
323                if let Some(arr) = self.array_states.get_mut(&array_idx) {
324                    if arr.item_btn_sel > 0 { arr.item_btn_sel -= 1; }
325                }
326                WizardEvent::None
327            }
328            KeyCode::Right => {
329                if let Some(arr) = self.array_states.get_mut(&array_idx) {
330                    if arr.item_btn_sel < 1 { arr.item_btn_sel += 1; }
331                }
332                WizardEvent::None
333            }
334            KeyCode::Enter => {
335                if items_len > 0 {
336                    if item_btn_sel == 1 {
337                        // [remove] focused
338                        let item_idx = selected.min(items_len - 1);
339                        if let Some(arr) = self.array_states.get_mut(&array_idx) {
340                            arr.items.remove(item_idx);
341                            if arr.items.is_empty() {
342                                arr.selected = 0;
343                            } else {
344                                arr.selected = arr.selected.min(arr.items.len() - 1);
345                            }
346                            arr.item_btn_sel = 0;
347                        }
348                        WizardEvent::ArrayItemDeleted { array_step_idx: array_idx, item_idx }
349                    } else {
350                        // Item itself focused — start editing
351                        let item_idx = selected.min(items_len - 1);
352                        self.array_start_edit(array_idx, sub_steps, item_idx)
353                    }
354                } else {
355                    WizardEvent::None
356                }
357            }
358            // Up/Down do nothing inside an expanded array nest
359            KeyCode::Up | KeyCode::Down => WizardEvent::None,
360            _ => WizardEvent::None,
361        }
362    }
363
364    // ── Array item edit ───────────────────────────────────────────────────────
365
366    fn handle_array_edit_key(
367        &mut self, key: KeyEvent,
368        array_idx: usize,
369        sub_steps: &'static [WizardStep],
370    ) -> WizardEvent {
371        let (sub_step, is_new, item_idx) = {
372            let s = self.array_states[&array_idx].editing.as_ref().unwrap();
373            (s.sub_step, s.is_new, s.item_idx)
374        };
375        let is_last_sub = sub_step + 1 >= sub_steps.len();
376
377        let sub_kind = match sub_steps.get(sub_step) {
378            None    => return WizardEvent::None,
379            Some(s) => match &s.kind {
380                WizardStepKind::Select(opts) => StepKindRef::Select(opts),
381                WizardStepKind::Optional     => StepKindRef::Optional,
382                _                            => StepKindRef::Leaf,
383            },
384        };
385
386        match sub_kind {
387            StepKindRef::Leaf | StepKindRef::Optional => {
388                self.handle_array_edit_leaf(key, array_idx, sub_steps, sub_step, item_idx, is_new, is_last_sub)
389            }
390            StepKindRef::Select(opts) => {
391                self.handle_array_edit_select(key, array_idx, sub_steps, sub_step, item_idx, is_new, is_last_sub, opts)
392            }
393            _ => WizardEvent::None,
394        }
395    }
396
397    fn handle_array_edit_leaf(
398        &mut self, key: KeyEvent,
399        array_idx: usize,
400        sub_steps: &'static [WizardStep],
401        sub_step: usize, item_idx: usize, is_new: bool, is_last_sub: bool,
402    ) -> WizardEvent {
403        match key.code {
404            KeyCode::Char(c) => {
405                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
406                s.buffer.insert(s.buf_cursor, c);
407                s.buf_cursor += c.len_utf8();
408                WizardEvent::None
409            }
410            KeyCode::Backspace => {
411                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
412                if s.buf_cursor > 0 {
413                    let start = prev_char_boundary(&s.buffer, s.buf_cursor);
414                    let len   = s.buf_cursor - start;
415                    s.buffer.drain(start..s.buf_cursor);
416                    s.buf_cursor -= len;
417                }
418                WizardEvent::None
419            }
420            KeyCode::Delete => {
421                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
422                if s.buf_cursor < s.buffer.len() { s.buffer.remove(s.buf_cursor); }
423                WizardEvent::None
424            }
425            KeyCode::Left => {
426                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
427                if s.buf_cursor > 0 { s.buf_cursor = prev_char_boundary(&s.buffer, s.buf_cursor); }
428                WizardEvent::None
429            }
430            KeyCode::Right => {
431                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
432                if s.buf_cursor < s.buffer.len() { s.buf_cursor = next_char_boundary(&s.buffer, s.buf_cursor); }
433                WizardEvent::None
434            }
435            KeyCode::Home => {
436                self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap().buf_cursor = 0;
437                WizardEvent::None
438            }
439            KeyCode::End => {
440                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
441                s.buf_cursor = s.buffer.len();
442                WizardEvent::None
443            }
444            KeyCode::Tab | KeyCode::Enter => {
445                let buf_val = self.array_states[&array_idx].editing.as_ref().unwrap().buffer.clone();
446                self.array_states.get_mut(&array_idx).unwrap().items[item_idx][sub_step] = buf_val;
447                if is_last_sub { self.complete_array_item(array_idx) }
448                else { self.advance_array_sub_step(array_idx, sub_steps, sub_step, item_idx) }
449            }
450            KeyCode::Esc => self.cancel_array_edit(array_idx, is_new, item_idx),
451            _ => WizardEvent::None,
452        }
453    }
454
455    fn handle_array_edit_select(
456        &mut self, key: KeyEvent,
457        array_idx: usize,
458        sub_steps: &'static [WizardStep],
459        sub_step: usize, item_idx: usize, is_new: bool, is_last_sub: bool,
460        opts: &'static [&'static str],
461    ) -> WizardEvent {
462        match key.code {
463            KeyCode::Left | KeyCode::Char('h') | KeyCode::BackTab => {
464                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
465                s.select_idx = if s.select_idx > 0 { s.select_idx - 1 } else { opts.len() - 1 };
466                let si = s.select_idx;
467                self.array_states.get_mut(&array_idx).unwrap().items[item_idx][sub_step] = opts[si].to_string();
468                WizardEvent::None
469            }
470            KeyCode::Right | KeyCode::Char('l') => {
471                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
472                s.select_idx = (s.select_idx + 1) % opts.len();
473                let si = s.select_idx;
474                self.array_states.get_mut(&array_idx).unwrap().items[item_idx][sub_step] = opts[si].to_string();
475                WizardEvent::None
476            }
477            KeyCode::Tab | KeyCode::Enter => {
478                let si = self.array_states[&array_idx].editing.as_ref().unwrap().select_idx;
479                self.array_states.get_mut(&array_idx).unwrap().items[item_idx][sub_step] = opts[si].to_string();
480                if is_last_sub { self.complete_array_item(array_idx) }
481                else { self.advance_array_sub_step(array_idx, sub_steps, sub_step, item_idx) }
482            }
483            KeyCode::Esc => self.cancel_array_edit(array_idx, is_new, item_idx),
484            _ => WizardEvent::None,
485        }
486    }
487
488    // ── Array helpers ─────────────────────────────────────────────────────────
489
490    fn make_initial_item_vals(&self, sub_steps: &'static [WizardStep]) -> Vec<String> {
491        sub_steps.iter().map(|s| match &s.kind {
492            WizardStepKind::Select(opts) => opts.first().copied().unwrap_or("").to_string(),
493            _ => String::new(),
494        }).collect()
495    }
496
497    fn array_start_add(&mut self, array_idx: usize, sub_steps: &'static [WizardStep]) -> WizardEvent {
498        let initial_vals = self.make_initial_item_vals(sub_steps);
499        let first_select_idx = match sub_steps.first().map(|s| &s.kind) {
500            Some(WizardStepKind::Select(opts)) =>
501                opts.iter().position(|&o| o == initial_vals[0].as_str()).unwrap_or(0),
502            _ => 0,
503        };
504        let sub_count = sub_steps.len();
505        let arr = self.array_states.entry(array_idx).or_insert_with(ArrayState::new);
506        arr.expanded = true;
507        let item_idx = arr.items.len();
508        arr.items.push(initial_vals);
509        arr.selected = item_idx; // focus the new item
510        arr.editing = Some(ArrayEditSession {
511            item_idx,
512            sub_step: 0,
513            is_new: true,
514            original_values: vec![String::new(); sub_count],
515            buffer: String::new(),
516            buf_cursor: 0,
517            select_idx: first_select_idx,
518        });
519        WizardEvent::ArrayItemAdded { array_step_idx: array_idx, item_idx }
520    }
521
522    fn array_start_edit(
523        &mut self, array_idx: usize,
524        sub_steps: &'static [WizardStep],
525        item_idx: usize,
526    ) -> WizardEvent {
527        let arr  = self.array_states.entry(array_idx).or_insert_with(ArrayState::new);
528        let orig = arr.items[item_idx].clone();
529        let first_val = orig.first().cloned().unwrap_or_default();
530        let first_select_idx = match sub_steps.first().map(|s| &s.kind) {
531            Some(WizardStepKind::Select(opts)) =>
532                opts.iter().position(|&o| o == first_val.as_str()).unwrap_or(0),
533            _ => 0,
534        };
535        arr.editing = Some(ArrayEditSession {
536            item_idx,
537            sub_step: 0,
538            is_new: false,
539            original_values: orig,
540            buffer: first_val.clone(),
541            buf_cursor: first_val.len(),
542            select_idx: first_select_idx,
543        });
544        WizardEvent::None
545    }
546
547    fn advance_array_sub_step(
548        &mut self, array_idx: usize,
549        sub_steps: &'static [WizardStep],
550        current_sub: usize, item_idx: usize,
551    ) -> WizardEvent {
552        let next_sub = current_sub + 1;
553        let next_val = self.array_states[&array_idx].items[item_idx][next_sub].clone();
554        match sub_steps[next_sub].kind {
555            WizardStepKind::Select(opts) => {
556                let si = opts.iter().position(|&o| o == next_val.as_str()).unwrap_or(0);
557                let s  = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
558                s.sub_step   = next_sub;
559                s.select_idx = si;
560                if next_val.is_empty() {
561                    self.array_states.get_mut(&array_idx).unwrap().items[item_idx][next_sub] = opts[si].to_string();
562                }
563            }
564            _ => {
565                let s = self.array_states.get_mut(&array_idx).unwrap().editing.as_mut().unwrap();
566                s.sub_step   = next_sub;
567                s.buffer     = next_val;
568                s.buf_cursor = s.buffer.len();
569            }
570        }
571        WizardEvent::None
572    }
573
574    fn complete_array_item(&mut self, array_idx: usize) -> WizardEvent {
575        let arr     = self.array_states.get_mut(&array_idx).unwrap();
576        let session = arr.editing.take().unwrap();
577        let item_idx = session.item_idx;
578        let values   = arr.items[item_idx].clone();
579        arr.selected  = item_idx; // keep focus on the just-completed item
580        WizardEvent::ArrayItemCompleted { array_step_idx: array_idx, item_idx, values }
581    }
582
583    fn cancel_array_edit(&mut self, array_idx: usize, is_new: bool, item_idx: usize) -> WizardEvent {
584        let arr     = self.array_states.get_mut(&array_idx).unwrap();
585        let session = arr.editing.take().unwrap();
586        if is_new {
587            arr.items.remove(item_idx);
588            arr.selected = if arr.items.is_empty() { 0 } else { arr.selected.min(arr.items.len() - 1) };
589            WizardEvent::ArrayItemDeleted { array_step_idx: array_idx, item_idx }
590        } else {
591            arr.items[item_idx] = session.original_values;
592            arr.selected = item_idx;
593            WizardEvent::None
594        }
595    }
596
597    fn array_advance_wizard(&mut self, _array_idx: usize) -> WizardEvent {
598        let index = self.current;
599        self.commit_value(String::new());
600        self.current += 1;
601        self.reset_array_on_arrival();
602        if self.is_complete() { WizardEvent::Done(self.values.clone()) }
603        else { WizardEvent::StepCompleted { index, value: String::new() } }
604    }
605
606    fn array_retreat_wizard(&mut self) {
607        if self.current > 0 {
608            self.current -= 1;
609        } else {
610            self.current = self.input_count.saturating_sub(1);
611        }
612        self.load_buffer_for(self.current);
613        self.reset_array_on_arrival();
614    }
615}