aboutsummaryrefslogtreecommitdiff
path: root/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/app')
-rw-r--r--src/app/input.rs10
-rw-r--r--src/app/state.rs58
2 files changed, 60 insertions, 8 deletions
diff --git a/src/app/input.rs b/src/app/input.rs
index c91722f7..254b7916 100644
--- a/src/app/input.rs
+++ b/src/app/input.rs
@@ -8,7 +8,7 @@ use tracing::warn;
use crate::layout::{NavDirection, PaneInfo, SplitBorder};
use crate::selection::Selection;
-use super::state::{AppState, ContextMenuState, DragState, Mode, CONTEXT_MENU_ITEMS};
+use super::state::{key_matches, AppState, ContextMenuState, DragState, Mode, CONTEXT_MENU_ITEMS};
use super::App;
// ---------------------------------------------------------------------------
@@ -86,19 +86,19 @@ fn handle_navigate_key(state: &mut AppState, key: KeyEvent) {
// Configurable keybinds (checked before fixed binds)
let kb = &state.keybinds;
- if key.code == kb.split_vertical.0 && key.modifiers.contains(kb.split_vertical.1) {
+ if key_matches(&key, kb.split_vertical.0, kb.split_vertical.1) {
state.split_pane(Direction::Horizontal);
return;
}
- if key.code == kb.split_horizontal.0 && key.modifiers.contains(kb.split_horizontal.1) {
+ if key_matches(&key, kb.split_horizontal.0, kb.split_horizontal.1) {
state.split_pane(Direction::Vertical);
return;
}
- if key.code == kb.close_pane.0 && key.modifiers.contains(kb.close_pane.1) {
+ if key_matches(&key, kb.close_pane.0, kb.close_pane.1) {
state.close_pane();
return;
}
- if key.code == kb.fullscreen.0 && key.modifiers.contains(kb.fullscreen.1) {
+ if key_matches(&key, kb.fullscreen.0, kb.fullscreen.1) {
state.toggle_fullscreen();
return;
}
diff --git a/src/app/state.rs b/src/app/state.rs
index 92d729e8..7a577bb8 100644
--- a/src/app/state.rs
+++ b/src/app/state.rs
@@ -75,7 +75,7 @@ pub struct AppState {
impl AppState {
pub fn is_prefix(&self, key: &crossterm::event::KeyEvent) -> bool {
- key.code == self.prefix_code && key.modifiers.contains(self.prefix_mods)
+ key_matches(key, self.prefix_code, self.prefix_mods)
}
pub fn estimate_pane_size(&self) -> (u16, u16) {
@@ -87,6 +87,25 @@ impl AppState {
}
}
+pub fn key_matches(
+ key: &crossterm::event::KeyEvent,
+ expected_code: KeyCode,
+ expected_mods: KeyModifiers,
+) -> bool {
+ if key.modifiers != expected_mods {
+ return false;
+ }
+
+ match (key.code, expected_code) {
+ (KeyCode::Char(actual), KeyCode::Char(expected))
+ if actual.is_ascii_alphabetic() && expected.is_ascii_alphabetic() =>
+ {
+ actual.eq_ignore_ascii_case(&expected)
+ }
+ (actual, expected) => actual == expected,
+ }
+}
+
// ---------------------------------------------------------------------------
// Test helpers
// ---------------------------------------------------------------------------
@@ -113,9 +132,9 @@ impl AppState {
context_menu: None,
update_available: None,
update_dismissed: false,
- prefix_code: KeyCode::Char('s'),
+ prefix_code: KeyCode::Char('b'),
prefix_mods: KeyModifiers::CONTROL,
- prefix_label: "ctrl+s".into(),
+ prefix_label: "ctrl+b".into(),
sidebar_width: 26,
sidebar_collapsed: false,
confirm_close: true,
@@ -133,3 +152,36 @@ impl AppState {
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crossterm::event::KeyEvent;
+
+ #[test]
+ fn key_matches_requires_exact_modifiers() {
+ assert!(key_matches(
+ &KeyEvent::new(KeyCode::Char('b'), KeyModifiers::CONTROL),
+ KeyCode::Char('b'),
+ KeyModifiers::CONTROL,
+ ));
+
+ assert!(!key_matches(
+ &KeyEvent::new(
+ KeyCode::Char('b'),
+ KeyModifiers::CONTROL | KeyModifiers::SHIFT,
+ ),
+ KeyCode::Char('b'),
+ KeyModifiers::CONTROL,
+ ));
+ }
+
+ #[test]
+ fn key_matches_letters_case_insensitively() {
+ assert!(key_matches(
+ &KeyEvent::new(KeyCode::Char('B'), KeyModifiers::SHIFT),
+ KeyCode::Char('b'),
+ KeyModifiers::SHIFT,
+ ));
+ }
+}