| 113 |
113 |
|
false
|
| 114 |
114 |
|
}
|
| 115 |
115 |
|
|
|
116 |
+ |
/// The user pressed `q` with no text field open.
|
|
117 |
+ |
///
|
|
118 |
+ |
/// Default is to close the console, which is what `q` has always meant.
|
|
119 |
+ |
/// The hook exists for the same reason [`cancel`](View::cancel) does, one
|
|
120 |
+ |
/// step further out: a view holding unsaved edits has a question to ask
|
|
121 |
+ |
/// before the answer to `q` is "yes, discard them". Before this the shell
|
|
122 |
+ |
/// returned from the loop itself and the view never saw the key.
|
|
123 |
+ |
fn quit(&mut self) -> Flow {
|
|
124 |
+ |
Flow::Exit
|
|
125 |
+ |
}
|
|
126 |
+ |
|
| 116 |
127 |
|
/// The user confirmed the modal this view raised with [`Flow::Confirm`].
|
| 117 |
128 |
|
///
|
| 118 |
|
- |
/// Default is nothing, so a view with no destructive actions ignores the
|
| 119 |
|
- |
/// whole mechanism.
|
| 120 |
|
- |
fn confirmed(&mut self, _log: &mut CommandLog) {}
|
|
129 |
+ |
/// Returns a [`Flow`] because the answer to a confirm can be to leave:
|
|
130 |
+ |
/// "discard your edits and quit?" is one question, and a view that could
|
|
131 |
+ |
/// only ever continue would have to ask it and then wait to be asked again.
|
|
132 |
+ |
///
|
|
133 |
+ |
/// Default is to carry on, so a view with no destructive actions ignores
|
|
134 |
+ |
/// the whole mechanism.
|
|
135 |
+ |
fn confirmed(&mut self, _log: &mut CommandLog) -> Flow {
|
|
136 |
+ |
Flow::Continue
|
|
137 |
+ |
}
|
| 121 |
138 |
|
|
| 122 |
139 |
|
/// The user dismissed the modal this view raised.
|
| 123 |
140 |
|
///
|
| 205 |
222 |
|
match modal_key(action) {
|
| 206 |
223 |
|
ModalOutcome::Confirmed => {
|
| 207 |
224 |
|
modal = None;
|
| 208 |
|
- |
view.confirmed(log);
|
|
225 |
+ |
match view.confirmed(log) {
|
|
226 |
+ |
Flow::Exit => return Ok(()),
|
|
227 |
+ |
Flow::Confirm(raised) => modal = Some(raised),
|
|
228 |
+ |
Flow::Suspend(command) => suspend(terminal, view, log, command)?,
|
|
229 |
+ |
Flow::Continue => {}
|
|
230 |
+ |
}
|
| 209 |
231 |
|
}
|
| 210 |
232 |
|
ModalOutcome::Cancelled => {
|
| 211 |
233 |
|
modal = None;
|
| 220 |
242 |
|
// decided first and the flow it produces is handled in one place.
|
| 221 |
243 |
|
let flow = match reserved(action, view.text_entry()) {
|
| 222 |
244 |
|
Reserved::Cancel => view.cancel(),
|
| 223 |
|
- |
Reserved::Quit => Flow::Exit,
|
|
245 |
+ |
Reserved::Quit => view.quit(),
|
| 224 |
246 |
|
Reserved::Pass => view.handle(key, log),
|
| 225 |
247 |
|
};
|
| 226 |
248 |
|
|
| 405 |
427 |
|
fn handle(&mut self, _key: KeyEvent, _log: &mut CommandLog) -> Flow {
|
| 406 |
428 |
|
Flow::Continue
|
| 407 |
429 |
|
}
|
| 408 |
|
- |
fn confirmed(&mut self, _log: &mut CommandLog) {
|
|
430 |
+ |
fn confirmed(&mut self, _log: &mut CommandLog) -> Flow {
|
| 409 |
431 |
|
self.confirmed += 1;
|
|
432 |
+ |
Flow::Continue
|
| 410 |
433 |
|
}
|
| 411 |
434 |
|
fn cancelled(&mut self) {
|
| 412 |
435 |
|
self.cancelled += 1;
|
| 413 |
436 |
|
}
|
| 414 |
437 |
|
}
|
| 415 |
438 |
|
|
|
439 |
+ |
// `q` reaches the view for the same reason Esc does. A view with unsaved
|
|
440 |
+ |
// edits answers it with a question; one without keeps the old meaning,
|
|
441 |
+ |
// which is what the default is.
|
|
442 |
+ |
#[test]
|
|
443 |
+ |
fn the_default_answer_to_q_is_still_to_close() {
|
|
444 |
+ |
let mut view = StubView::default();
|
|
445 |
+ |
assert!(matches!(view.quit(), Flow::Exit));
|
|
446 |
+ |
}
|
|
447 |
+ |
|
| 416 |
448 |
|
#[test]
|
| 417 |
449 |
|
fn enter_confirms_and_esc_cancels() {
|
| 418 |
450 |
|
assert_eq!(modal_key(Action::Activate), ModalOutcome::Confirmed);
|
| 456 |
488 |
|
let mut view = StubView::default();
|
| 457 |
489 |
|
let mut log = CommandLog::new();
|
| 458 |
490 |
|
|
| 459 |
|
- |
view.confirmed(&mut log);
|
|
491 |
+ |
let _ = view.confirmed(&mut log);
|
| 460 |
492 |
|
view.cancelled();
|
| 461 |
493 |
|
|
| 462 |
494 |
|
assert_eq!(view.confirmed, 1);
|