use crate::DataProvider;
use crate::canvas::actions::{ActionResult, CanvasAction};
use crate::canvas::modes::AppMode;
use crate::textform::TextFormState;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BoundaryExit {
Top,
Bottom,
}
#[derive(Debug, Clone)]
pub enum HostActionOutcome {
Applied(ActionResult),
ExitCanvas(BoundaryExit),
}
pub fn execute_action_for_host<D: DataProvider>(
editor: &mut TextFormState<D>,
action: CanvasAction,
) -> HostActionOutcome {
execute_action_for_host_with_options(editor, action, true)
}
pub fn execute_action_for_host_with_options<D: DataProvider>(
editor: &mut TextFormState<D>,
action: CanvasAction,
allow_exit_in_read_only: bool,
) -> HostActionOutcome {
let allow_exit = allow_exit_in_read_only && editor.mode() == AppMode::Nor;
match action {
CanvasAction::MoveDown | CanvasAction::NextField => {
let last = editor.data_provider().field_count().saturating_sub(1);
let at_bottom = editor.current_field() >= last;
if allow_exit && at_bottom {
HostActionOutcome::ExitCanvas(BoundaryExit::Bottom)
} else {
let _ = editor.move_down();
HostActionOutcome::Applied(ActionResult::Success)
}
}
CanvasAction::MoveUp | CanvasAction::PrevField => {
let at_top = editor.current_field() == 0;
if allow_exit && at_top {
HostActionOutcome::ExitCanvas(BoundaryExit::Top)
} else {
let _ = editor.move_up();
HostActionOutcome::Applied(ActionResult::Success)
}
}
other => HostActionOutcome::Applied(editor.execute(other)),
}
}
#[cfg(feature = "keybindings")]
use crate::keybindings::KeyEventOutcome;
#[cfg(feature = "keybindings")]
use crossterm::event::KeyEvent;
#[cfg(feature = "keybindings")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HostKeyEventOutcome {
Consumed(Option<String>),
PendingSequence,
NotHandled,
ExitCanvas(BoundaryExit),
}
#[cfg(feature = "keybindings")]
pub fn map_key_event_outcome_for_host(outcome: KeyEventOutcome) -> HostKeyEventOutcome {
match outcome {
KeyEventOutcome::Consumed(msg) => HostKeyEventOutcome::Consumed(msg),
KeyEventOutcome::Pending => HostKeyEventOutcome::PendingSequence,
KeyEventOutcome::NotMatched => HostKeyEventOutcome::NotHandled,
KeyEventOutcome::ExitTop => HostKeyEventOutcome::ExitCanvas(BoundaryExit::Top),
KeyEventOutcome::ExitBottom => HostKeyEventOutcome::ExitCanvas(BoundaryExit::Bottom),
}
}
#[cfg(feature = "keybindings")]
pub fn handle_key_event_for_host<D: DataProvider>(
editor: &mut TextFormState<D>,
evt: KeyEvent,
) -> HostKeyEventOutcome {
let outcome = map_key_event_outcome_for_host(editor.handle_key_event(evt));
if editor.mode() != AppMode::Nor && matches!(outcome, HostKeyEventOutcome::ExitCanvas(_)) {
HostKeyEventOutcome::NotHandled
} else {
outcome
}
}
#[cfg(feature = "keybindings")]
pub fn boundary_from_key_outcome(outcome: &KeyEventOutcome) -> Option<BoundaryExit> {
match outcome {
KeyEventOutcome::ExitTop => Some(BoundaryExit::Top),
KeyEventOutcome::ExitBottom => Some(BoundaryExit::Bottom),
_ => None,
}
}
#[cfg(feature = "keybindings")]
pub fn key_outcome_for_vertical_navigation(moved: bool, boundary: BoundaryExit) -> KeyEventOutcome {
if moved {
KeyEventOutcome::Consumed(None)
} else {
match boundary {
BoundaryExit::Top => KeyEventOutcome::ExitTop,
BoundaryExit::Bottom => KeyEventOutcome::ExitBottom,
}
}
}