use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use super::edit_action::EditAction;
pub struct BufferState {
pub is_empty: bool,
pub at_end: bool,
pub has_suggestion: bool,
pub last_action: EditAction,
}
pub struct Keymap {
numeric_arg: Option<u32>,
}
impl Default for Keymap {
fn default() -> Self {
Self::new()
}
}
impl Keymap {
pub fn new() -> Self {
Self { numeric_arg: None }
}
#[allow(dead_code)] pub fn pending_numeric_arg(&self) -> Option<u32> {
self.numeric_arg
}
pub fn resolve(&mut self, key: KeyEvent, state: &BufferState) -> (EditAction, u32) {
let mods = key.modifiers;
let ctrl = mods.contains(KeyModifiers::CONTROL);
let alt = mods.contains(KeyModifiers::ALT);
if alt
&& !ctrl
&& let KeyCode::Char(ch) = key.code
&& let Some(digit) = ch.to_digit(10)
{
let current = self.numeric_arg.unwrap_or(0);
self.numeric_arg = Some(current * 10 + digit);
return (EditAction::SetNumericArg(digit as u8), 1);
}
if ctrl && key.code == KeyCode::Char('g') {
self.numeric_arg = None;
return (EditAction::Cancel, 1);
}
let count = self.numeric_arg.take().unwrap_or(1);
let action = match (key.code, ctrl, alt) {
(KeyCode::Char('a'), true, false) => EditAction::MoveToStart,
(KeyCode::Char('b'), true, false) => EditAction::MoveBackward,
(KeyCode::Char('c'), true, false) => EditAction::Interrupt,
(KeyCode::Char('d'), true, false) => {
if state.is_empty {
EditAction::Eof
} else {
EditAction::DeleteForward
}
}
(KeyCode::Char('e'), true, false) => EditAction::MoveToEnd,
(KeyCode::Char('f'), true, false) => {
if state.at_end && state.has_suggestion {
EditAction::AcceptSuggestion
} else {
EditAction::MoveForward
}
}
(KeyCode::Char('j'), true, false) => EditAction::Submit,
(KeyCode::Char('k'), true, false) => EditAction::KillToEnd,
(KeyCode::Char('l'), true, false) => EditAction::ClearScreen,
(KeyCode::Char('r'), true, false) => EditAction::FuzzySearch,
(KeyCode::Char('t'), true, false) => EditAction::TransposeChars,
(KeyCode::Char('u'), true, false) => EditAction::KillToStart,
(KeyCode::Char('w'), true, false) => EditAction::KillBackwardWord,
(KeyCode::Char('y'), true, false) => EditAction::Yank,
(KeyCode::Char('_'), true, false) => EditAction::Undo,
(KeyCode::Char('b'), false, true) => EditAction::MoveBackwardWord,
(KeyCode::Char('c'), false, true) => EditAction::CapitalizeWord,
(KeyCode::Char('d'), false, true) => EditAction::KillForwardWord,
(KeyCode::Char('f'), false, true) => {
if state.has_suggestion {
EditAction::AcceptWordSuggestion
} else {
EditAction::MoveForwardWord
}
}
(KeyCode::Char('l'), false, true) => EditAction::DowncaseWord,
(KeyCode::Char('t'), false, true) => EditAction::TransposeWords,
(KeyCode::Char('u'), false, true) => EditAction::UpcaseWord,
(KeyCode::Char('y'), false, true) => {
if state.last_action == EditAction::Yank || state.last_action == EditAction::YankPop
{
EditAction::YankPop
} else {
EditAction::Noop
}
}
(KeyCode::Backspace, false, true) => EditAction::KillBackwardWord,
(KeyCode::Enter, false, false) => EditAction::Submit,
(KeyCode::Backspace, false, false) => EditAction::DeleteBackward,
(KeyCode::Delete, false, false) => EditAction::DeleteForward,
(KeyCode::Tab, false, false) => EditAction::TabComplete,
(KeyCode::Home, false, false) => EditAction::MoveToStart,
(KeyCode::End, false, false) => EditAction::MoveToEnd,
(KeyCode::Left, _, _) => EditAction::MoveBackward,
(KeyCode::Right, _, _) => {
if state.at_end && state.has_suggestion {
EditAction::AcceptSuggestion
} else {
EditAction::MoveForward
}
}
(KeyCode::Up, _, _) => EditAction::HistoryPrev,
(KeyCode::Down, _, _) => EditAction::HistoryNext,
(KeyCode::Char(ch), false, false) => EditAction::InsertChar(ch),
_ => EditAction::Noop,
};
(action, count)
}
}