use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
#[derive(Debug, Clone, PartialEq)]
pub enum Action {
NavigateUp,
NavigateDown,
NavigatePageUp,
NavigatePageDown,
NavigateTop,
NavigateBottom,
ToggleExpand,
CollapseParent,
StartEdit,
CancelEdit,
ConfirmEdit,
InsertChar(char),
Backspace,
Add,
Delete,
Undo,
Save,
Quit,
Search,
Help,
None,
}
pub fn handle_key(key: KeyEvent, editing: bool) -> Action {
if editing {
handle_editing_keys(key)
} else {
handle_browsing_keys(key)
}
}
fn handle_editing_keys(key: KeyEvent) -> Action {
match (key.code, key.modifiers) {
(KeyCode::Enter, KeyModifiers::NONE) => Action::ConfirmEdit,
(KeyCode::Esc, _) => Action::CancelEdit,
(KeyCode::Char(c), KeyModifiers::NONE | KeyModifiers::SHIFT) => Action::InsertChar(c),
(KeyCode::Backspace, _) => Action::Backspace,
(KeyCode::Char('c'), KeyModifiers::CONTROL) => Action::Quit,
_ => Action::None,
}
}
fn handle_browsing_keys(key: KeyEvent) -> Action {
match (key.code, key.modifiers) {
(KeyCode::Up, _) => Action::NavigateUp,
(KeyCode::Down, _) => Action::NavigateDown,
(KeyCode::Left, _) => Action::CollapseParent, (KeyCode::Right, _) => Action::ToggleExpand,
(KeyCode::Char('k'), KeyModifiers::NONE) => Action::NavigateUp,
(KeyCode::Char('j'), KeyModifiers::NONE) => Action::NavigateDown,
(KeyCode::Char('h'), KeyModifiers::NONE) => Action::CollapseParent,
(KeyCode::Char('l'), KeyModifiers::NONE) => Action::ToggleExpand,
(KeyCode::PageUp, _) | (KeyCode::Char('u'), KeyModifiers::CONTROL) => {
Action::NavigatePageUp
}
(KeyCode::PageDown, _) | (KeyCode::Char('d'), KeyModifiers::CONTROL) => {
Action::NavigatePageDown
}
(KeyCode::Home, _) | (KeyCode::Char('g'), KeyModifiers::NONE) => Action::NavigateTop,
(KeyCode::End, _) | (KeyCode::Char('G'), KeyModifiers::SHIFT) => Action::NavigateBottom,
(KeyCode::Enter, _) | (KeyCode::Char(' '), KeyModifiers::NONE) => Action::ToggleExpand,
(KeyCode::Char('e'), KeyModifiers::NONE) => Action::StartEdit,
(KeyCode::Char('a'), KeyModifiers::NONE) => Action::Add,
(KeyCode::Char('d'), KeyModifiers::NONE) => Action::Delete,
(KeyCode::Char('u'), KeyModifiers::NONE) => Action::Undo,
(KeyCode::Char('s'), KeyModifiers::NONE) | (KeyCode::Char('w'), KeyModifiers::CONTROL) => {
Action::Save
}
(KeyCode::Char('q'), KeyModifiers::NONE) | (KeyCode::Esc, _) => Action::Quit,
(KeyCode::Char('c'), KeyModifiers::CONTROL) => Action::Quit,
(KeyCode::Char('/'), KeyModifiers::NONE) => Action::Search,
(KeyCode::Char('?'), _) => Action::Help,
_ => Action::None,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn browse(c: char) -> Action {
handle_key(KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE), false)
}
#[test]
fn browsing_maps_tree_edit_keys() {
assert_eq!(browse('a'), Action::Add);
assert_eq!(browse('d'), Action::Delete);
assert_eq!(browse('u'), Action::Undo);
assert_eq!(browse('e'), Action::StartEdit);
assert_eq!(browse('/'), Action::Search);
}
#[test]
fn help_ignores_shift_modifier() {
assert_eq!(
handle_key(
KeyEvent::new(KeyCode::Char('?'), KeyModifiers::SHIFT),
false
),
Action::Help
);
}
#[test]
fn editing_keys_do_not_trigger_browse_actions() {
assert_eq!(
handle_key(KeyEvent::new(KeyCode::Char('a'), KeyModifiers::NONE), true),
Action::InsertChar('a')
);
}
}