use super::modes::Mode;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
#[derive(Debug, Clone, PartialEq)]
pub enum KeyAction {
EnterNormalMode,
EnterInsertMode,
EnterVisualMode,
EnterCommandMode,
MoveUp,
MoveDown,
MoveLeft,
MoveRight,
MoveToTop,
MoveToBottom,
MovePageUp,
MovePageDown,
ExpandNode,
CollapseNode,
ToggleNode,
DeleteChar,
DeleteLine,
DeleteNode,
InsertChar(char),
NewLine,
Backspace,
Save,
Quit,
SaveAndQuit,
ForceQuit,
ExecuteCommand(String),
SelectUp,
SelectDown,
SelectAll,
ShowHelp,
Refresh,
Undo,
Redo,
Repeat,
None,
}
pub struct KeyHandler;
impl KeyHandler {
pub fn handle(key: KeyEvent, mode: Mode) -> KeyAction {
match mode {
Mode::Normal => Self::handle_normal_mode(key),
Mode::Insert => Self::handle_insert_mode(key),
Mode::Visual => Self::handle_visual_mode(key),
Mode::Command => Self::handle_command_mode(key),
}
}
fn handle_normal_mode(key: KeyEvent) -> KeyAction {
match (key.code, key.modifiers) {
(KeyCode::Char('i'), KeyModifiers::NONE) => KeyAction::EnterInsertMode,
(KeyCode::Char('v'), KeyModifiers::NONE) => KeyAction::EnterVisualMode,
(KeyCode::Char(':'), KeyModifiers::NONE) => KeyAction::EnterCommandMode,
(KeyCode::Char('h'), KeyModifiers::NONE) => KeyAction::MoveLeft,
(KeyCode::Char('j'), KeyModifiers::NONE) => KeyAction::MoveDown,
(KeyCode::Char('k'), KeyModifiers::NONE) => KeyAction::MoveUp,
(KeyCode::Char('l'), KeyModifiers::NONE) => KeyAction::MoveRight,
(KeyCode::Left, _) => KeyAction::MoveLeft,
(KeyCode::Down, _) => KeyAction::MoveDown,
(KeyCode::Up, _) => KeyAction::MoveUp,
(KeyCode::Right, _) => KeyAction::MoveRight,
(KeyCode::Char('g'), KeyModifiers::NONE) => KeyAction::MoveToTop,
(KeyCode::Char('G'), KeyModifiers::SHIFT) => KeyAction::MoveToBottom,
(KeyCode::PageUp, _) | (KeyCode::Char('u'), KeyModifiers::CONTROL) => {
KeyAction::MovePageUp
}
(KeyCode::PageDown, _) | (KeyCode::Char('d'), KeyModifiers::CONTROL) => {
KeyAction::MovePageDown
}
(KeyCode::Home, _) => KeyAction::MoveToTop,
(KeyCode::End, _) => KeyAction::MoveToBottom,
(KeyCode::Enter, _) | (KeyCode::Char('o'), KeyModifiers::NONE) => KeyAction::ToggleNode,
(KeyCode::Char('O'), KeyModifiers::SHIFT) => KeyAction::ExpandNode,
(KeyCode::Char('C'), KeyModifiers::SHIFT) => KeyAction::CollapseNode,
(KeyCode::Char('d'), KeyModifiers::NONE) => KeyAction::DeleteNode,
(KeyCode::Char('x'), KeyModifiers::NONE) => KeyAction::DeleteChar,
(KeyCode::Delete, _) => KeyAction::DeleteChar,
(KeyCode::Char('w'), KeyModifiers::CONTROL) => KeyAction::Save,
(KeyCode::Char('q'), KeyModifiers::CONTROL) => KeyAction::Quit,
(KeyCode::Char('c'), KeyModifiers::CONTROL) => KeyAction::ForceQuit,
(KeyCode::Esc, KeyModifiers::NONE) => KeyAction::Quit,
(KeyCode::Char('u'), KeyModifiers::NONE) => KeyAction::Undo,
(KeyCode::Char('r'), KeyModifiers::CONTROL) => KeyAction::Redo,
(KeyCode::Char('.'), KeyModifiers::NONE) => KeyAction::Repeat,
(KeyCode::Char('?'), KeyModifiers::NONE) => KeyAction::ShowHelp,
(KeyCode::Char('r'), KeyModifiers::NONE) => KeyAction::Refresh,
_ => KeyAction::None,
}
}
fn handle_insert_mode(key: KeyEvent) -> KeyAction {
match (key.code, key.modifiers) {
(KeyCode::Esc, _) => KeyAction::EnterNormalMode,
(KeyCode::Char(c), KeyModifiers::NONE | KeyModifiers::SHIFT) => {
KeyAction::InsertChar(c)
}
(KeyCode::Backspace, _) => KeyAction::Backspace,
(KeyCode::Delete, _) => KeyAction::DeleteChar,
(KeyCode::Enter, _) => KeyAction::NewLine,
(KeyCode::Left, _) => KeyAction::MoveLeft,
(KeyCode::Right, _) => KeyAction::MoveRight,
(KeyCode::Up, _) => KeyAction::MoveUp,
(KeyCode::Down, _) => KeyAction::MoveDown,
_ => KeyAction::None,
}
}
fn handle_visual_mode(key: KeyEvent) -> KeyAction {
match (key.code, key.modifiers) {
(KeyCode::Esc, _) | (KeyCode::Char('v'), KeyModifiers::NONE) => {
KeyAction::EnterNormalMode
}
(KeyCode::Char('h'), KeyModifiers::NONE) => KeyAction::MoveLeft,
(KeyCode::Char('j'), KeyModifiers::NONE) => KeyAction::SelectDown,
(KeyCode::Char('k'), KeyModifiers::NONE) => KeyAction::SelectUp,
(KeyCode::Char('l'), KeyModifiers::NONE) => KeyAction::MoveRight,
(KeyCode::Up, _) => KeyAction::SelectUp,
(KeyCode::Down, _) => KeyAction::SelectDown,
(KeyCode::Char('a'), KeyModifiers::CONTROL) => KeyAction::SelectAll,
(KeyCode::Char('d'), KeyModifiers::NONE) => KeyAction::DeleteNode,
(KeyCode::Delete, _) | (KeyCode::Char('x'), KeyModifiers::NONE) => {
KeyAction::DeleteNode
}
_ => KeyAction::None,
}
}
fn handle_command_mode(key: KeyEvent) -> KeyAction {
match (key.code, key.modifiers) {
(KeyCode::Esc, _) => KeyAction::EnterNormalMode,
(KeyCode::Enter, _) => KeyAction::ExecuteCommand(String::new()),
(KeyCode::Char(c), KeyModifiers::NONE | KeyModifiers::SHIFT) => {
KeyAction::InsertChar(c)
}
(KeyCode::Backspace, _) => KeyAction::Backspace,
_ => KeyAction::None,
}
}
pub fn parse_command(cmd: &str) -> KeyAction {
let cmd = cmd.trim();
match cmd {
"w" | "write" => KeyAction::Save,
"q" | "quit" => KeyAction::Quit,
"wq" | "x" => KeyAction::SaveAndQuit,
"q!" | "quit!" => KeyAction::ForceQuit,
_ => KeyAction::None,
}
}
}