use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use crate::app::Action;
pub(super) fn action_for_key(key: KeyEvent) -> Option<Action> {
if key.modifiers.contains(KeyModifiers::CONTROL) && matches!(key.code, KeyCode::Char('c')) {
return Some(Action::Quit);
}
match key.code {
KeyCode::Char('?') | KeyCode::F(1) => Some(Action::Help),
KeyCode::Char('q') | KeyCode::Esc | KeyCode::Left => Some(Action::Cancel),
KeyCode::Down if key.modifiers.contains(KeyModifiers::SHIFT) => Some(Action::NextCommit),
KeyCode::Up if key.modifiers.contains(KeyModifiers::SHIFT) => Some(Action::PreviousCommit),
KeyCode::Char('j') | KeyCode::Down => Some(Action::Down),
KeyCode::Char('k') | KeyCode::Up => Some(Action::Up),
KeyCode::Enter | KeyCode::Right => Some(Action::Open),
KeyCode::Char('J') => Some(Action::NextCommit),
KeyCode::Char('K') => Some(Action::PreviousCommit),
KeyCode::Char('g') | KeyCode::Home => Some(Action::Top),
KeyCode::Char('G') | KeyCode::End => Some(Action::Bottom),
KeyCode::PageDown => Some(Action::PageDown),
KeyCode::PageUp => Some(Action::PageUp),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn key(code: KeyCode) -> KeyEvent {
KeyEvent::new(code, KeyModifiers::NONE)
}
fn shifted_key(code: KeyCode) -> KeyEvent {
KeyEvent::new(code, KeyModifiers::SHIFT)
}
fn control_key(code: KeyCode) -> KeyEvent {
KeyEvent::new(code, KeyModifiers::CONTROL)
}
#[test]
fn arrow_keys_map_to_navigation_actions() {
assert_eq!(action_for_key(key(KeyCode::Left)), Some(Action::Cancel));
assert_eq!(action_for_key(key(KeyCode::Right)), Some(Action::Open));
assert_eq!(action_for_key(key(KeyCode::Down)), Some(Action::Down));
assert_eq!(action_for_key(key(KeyCode::Up)), Some(Action::Up));
}
#[test]
fn documented_keys_map_to_expected_actions() {
assert_eq!(action_for_key(key(KeyCode::Enter)), Some(Action::Open));
assert_eq!(action_for_key(key(KeyCode::Right)), Some(Action::Open));
assert_eq!(action_for_key(key(KeyCode::Left)), Some(Action::Cancel));
assert_eq!(action_for_key(key(KeyCode::Esc)), Some(Action::Cancel));
assert_eq!(
action_for_key(key(KeyCode::Char('q'))),
Some(Action::Cancel)
);
assert_eq!(action_for_key(key(KeyCode::Char('j'))), Some(Action::Down));
assert_eq!(action_for_key(key(KeyCode::Char('k'))), Some(Action::Up));
assert_eq!(action_for_key(key(KeyCode::Down)), Some(Action::Down));
assert_eq!(action_for_key(key(KeyCode::Up)), Some(Action::Up));
assert_eq!(
action_for_key(key(KeyCode::Char('J'))),
Some(Action::NextCommit)
);
assert_eq!(
action_for_key(shifted_key(KeyCode::Down)),
Some(Action::NextCommit)
);
assert_eq!(
action_for_key(key(KeyCode::Char('K'))),
Some(Action::PreviousCommit)
);
assert_eq!(
action_for_key(shifted_key(KeyCode::Up)),
Some(Action::PreviousCommit)
);
assert_eq!(action_for_key(key(KeyCode::Char('g'))), Some(Action::Top));
assert_eq!(action_for_key(key(KeyCode::Home)), Some(Action::Top));
assert_eq!(
action_for_key(key(KeyCode::Char('G'))),
Some(Action::Bottom)
);
assert_eq!(action_for_key(key(KeyCode::End)), Some(Action::Bottom));
assert_eq!(
action_for_key(key(KeyCode::PageDown)),
Some(Action::PageDown)
);
assert_eq!(action_for_key(key(KeyCode::PageUp)), Some(Action::PageUp));
assert_eq!(action_for_key(key(KeyCode::Char('?'))), Some(Action::Help));
assert_eq!(action_for_key(key(KeyCode::F(1))), Some(Action::Help));
assert_eq!(
action_for_key(control_key(KeyCode::Char('c'))),
Some(Action::Quit)
);
}
#[test]
fn shifted_arrows_map_to_commit_switching() {
assert_eq!(
action_for_key(shifted_key(KeyCode::Down)),
Some(Action::NextCommit)
);
assert_eq!(
action_for_key(shifted_key(KeyCode::Up)),
Some(Action::PreviousCommit)
);
}
#[test]
fn help_keys_map_to_help_action() {
assert_eq!(action_for_key(key(KeyCode::Char('?'))), Some(Action::Help));
assert_eq!(action_for_key(key(KeyCode::F(1))), Some(Action::Help));
assert_eq!(action_for_key(key(KeyCode::Char('h'))), None);
}
}