diff --git a/src/command/keymap.rs b/src/command/keymap.rs index f258717..a1aab5b 100644 --- a/src/command/keymap.rs +++ b/src/command/keymap.rs @@ -6,6 +6,7 @@ use crossterm::event::{KeyCode, KeyModifiers}; use crate::ui::app::AppMode; use crate::ui::effect::Effect; +use crate::view::Axis; use super::cmd::{self, Cmd, CmdContext}; @@ -14,6 +15,9 @@ use super::cmd::{self, Cmd, CmdContext}; pub enum KeyPattern { /// Single key with modifiers Key(KeyCode, KeyModifiers), + /// Matches any Char key (for text-entry modes). The actual char + /// is available in CmdContext::key_code. + AnyChar, } /// Identifies which mode a binding applies to. @@ -22,14 +26,35 @@ pub enum KeyPattern { pub enum ModeKey { Normal, Help, - // More modes can be added as we migrate handlers + FormulaPanel, + CategoryPanel, + ViewPanel, + TileSelect, + Editing, + FormulaEdit, + CategoryAdd, + ItemAdd, + ExportPrompt, + CommandMode, + SearchMode, } impl ModeKey { - pub fn from_app_mode(mode: &AppMode) -> Option { + pub fn from_app_mode(mode: &AppMode, search_mode: bool) -> Option { match mode { + AppMode::Normal if search_mode => Some(ModeKey::SearchMode), AppMode::Normal => Some(ModeKey::Normal), AppMode::Help => Some(ModeKey::Help), + AppMode::FormulaPanel => Some(ModeKey::FormulaPanel), + AppMode::CategoryPanel => Some(ModeKey::CategoryPanel), + AppMode::ViewPanel => Some(ModeKey::ViewPanel), + AppMode::TileSelect => Some(ModeKey::TileSelect), + AppMode::Editing { .. } => Some(ModeKey::Editing), + AppMode::FormulaEdit { .. } => Some(ModeKey::FormulaEdit), + AppMode::CategoryAdd { .. } => Some(ModeKey::CategoryAdd), + AppMode::ItemAdd { .. } => Some(ModeKey::ItemAdd), + AppMode::ExportPrompt { .. } => Some(ModeKey::ExportPrompt), + AppMode::CommandMode { .. } => Some(ModeKey::CommandMode), _ => None, } } @@ -77,9 +102,22 @@ impl Keymap { pub fn lookup(&self, key: KeyCode, mods: KeyModifiers) -> Option<&dyn Cmd> { self.bindings .get(&KeyPattern::Key(key, mods)) + .or_else(|| { + // Fall back to AnyChar for text-entry modes + if matches!(key, KeyCode::Char(_)) { + self.bindings.get(&KeyPattern::AnyChar) + } else { + None + } + }) .map(|c| c.as_ref()) } + /// Bind a catch-all for any Char key (used for text-entry modes). + pub fn bind_any_char(&mut self, cmd: impl Cmd + 'static) { + self.bindings.insert(KeyPattern::AnyChar, Arc::new(cmd)); + } + /// Execute a keymap lookup and return effects, or None if no binding. pub fn dispatch( &self, @@ -133,8 +171,8 @@ impl KeymapSet { } /// Look up the root keymap for a given app mode. - pub fn get(&self, mode: &AppMode) -> Option<&Arc> { - let mode_key = ModeKey::from_app_mode(mode)?; + pub fn get(&self, mode: &AppMode, search_mode: bool) -> Option<&Arc> { + let mode_key = ModeKey::from_app_mode(mode, search_mode)?; self.mode_maps.get(&mode_key) } @@ -145,7 +183,7 @@ impl KeymapSet { key: KeyCode, mods: KeyModifiers, ) -> Option>> { - let keymap = self.get(ctx.mode)?; + let keymap = self.get(ctx.mode, ctx.search_mode)?; keymap.dispatch(ctx, key, mods) }