diff --git a/client/config.toml b/client/config.toml index d096d83..764dd4b 100644 --- a/client/config.toml +++ b/client/config.toml @@ -5,6 +5,7 @@ enter_command_mode = [":", "ctrl+;"] next_buffer = ["space+b+n"] previous_buffer = ["space+b+p"] close_buffer = ["space+b+d"] +revert = ["space+b+r"] [keybindings.general] up = ["k", "Up"] @@ -27,7 +28,6 @@ move_up = ["Up"] move_down = ["Down"] toggle_sidebar = ["ctrl+t"] toggle_buffer_list = ["ctrl+b"] -revert = ["space+b+r"] # MODE SPECIFIC # READ ONLY MODE @@ -60,7 +60,7 @@ prev_field = ["Shift+Tab"] [keybindings.highlight] exit_highlight_mode = ["esc"] -enter_highlight_mode_linewise = ["ctrl+v"] +enter_highlight_mode_linewise = ["shift+v"] ### AUTOGENERATED CANVAS CONFIG # Required diff --git a/client/src/config/binds/config.rs b/client/src/config/binds/config.rs index 6ce2ad6..c338439 100644 --- a/client/src/config/binds/config.rs +++ b/client/src/config/binds/config.rs @@ -250,28 +250,44 @@ impl Config { key: KeyCode, modifiers: KeyModifiers, ) -> bool { - // Special handling for shift+character combinations - if binding.to_lowercase().starts_with("shift+") { + + // Normalize binding once + let binding_lc = binding.to_lowercase(); + + // Robust handling for Shift+Tab + // Accept either BackTab (with or without SHIFT flagged) or Tab+SHIFT + if binding_lc == "shift+tab" || binding_lc == "backtab" { + return match key { + KeyCode::BackTab => true, + KeyCode::Tab => modifiers.contains(KeyModifiers::SHIFT), + _ => false, + }; + } + + // Robust handling for shift+ (letters) + // Many terminals send uppercase Char without SHIFT bit. + if binding_lc.starts_with("shift+") { let parts: Vec<&str> = binding.split('+').collect(); - if parts.len() == 2 && parts[1].len() == 1 { - let expected_lowercase = parts[1].chars().next().unwrap().to_lowercase().next().unwrap(); - let expected_uppercase = expected_lowercase.to_uppercase().next().unwrap(); - if let KeyCode::Char(actual_char) = key { - if actual_char == expected_uppercase && modifiers.contains(KeyModifiers::SHIFT) { + if parts.len() == 2 && parts[1].chars().count() == 1 { + let base = parts[1].chars().next().unwrap(); + let upper = base.to_ascii_uppercase(); + let lower = base.to_ascii_lowercase(); + if let KeyCode::Char(actual) = key { + // Accept uppercase char regardless of SHIFT bit + if actual == upper { + return true; + } + // Also accept lowercase char with SHIFT flagged (some terms do this) + if actual == lower && modifiers.contains(KeyModifiers::SHIFT) { return true; } } } } - // Handle Shift+Tab -> BackTab - if binding.to_lowercase() == "shift+tab" && key == KeyCode::BackTab && modifiers.is_empty() { - return true; - } - // Handle multi-character bindings (all standard keys without modifiers) if binding.len() > 1 && !binding.contains('+') { - return match binding.to_lowercase().as_str() { + return match binding_lc.as_str() { // Navigation keys "left" => key == KeyCode::Left, "right" => key == KeyCode::Right, @@ -371,6 +387,7 @@ impl Config { let mut expected_key = None; for part in parts { + let part_lc = part.to_lowercase(); match part.to_lowercase().as_str() { // Modifiers "ctrl" | "control" => expected_modifiers |= KeyModifiers::CONTROL, @@ -789,12 +806,43 @@ impl Config { None } + // Normalize bindings for canvas consumption: + // - "shift+" -> also add "" + // - "shift+tab" -> also add "backtab" + // This keeps your config human-friendly while making the canvas happy. + fn normalize_for_canvas( + map: &HashMap>, + ) -> HashMap> { + let mut out: HashMap> = HashMap::new(); + for (action, bindings) in map { + let mut new_list: Vec = Vec::new(); + for b in bindings { + new_list.push(b.clone()); + let blc = b.to_lowercase(); + if blc.starts_with("shift+") { + let parts: Vec<&str> = b.split('+').collect(); + if parts.len() == 2 && parts[1].chars().count() == 1 { + let ch = parts[1].chars().next().unwrap(); + new_list.push(ch.to_ascii_uppercase().to_string()); + } + if blc == "shift+tab" { + new_list.push("backtab".to_string()); + } + } + if blc == "shift+tab" { + new_list.push("backtab".to_string()); + } + } + out.insert(action.clone(), new_list); + } + out + } + pub fn build_canvas_keymap(&self) -> CanvasKeyMap { - CanvasKeyMap::from_mode_maps( - &self.keybindings.read_only, - &self.keybindings.edit, - &self.keybindings.highlight, - ) + let ro = Self::normalize_for_canvas(&self.keybindings.read_only); + let ed = Self::normalize_for_canvas(&self.keybindings.edit); + let hl = Self::normalize_for_canvas(&self.keybindings.highlight); + CanvasKeyMap::from_mode_maps(&ro, &ed, &hl) } } diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index cd440f1..9c99f9d 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -574,6 +574,16 @@ impl EventHandler { ); return Ok(EventOutcome::Ok(message)); } + "revert" | "save" | "force_quit" | "save_and_quit" => { + let outcome = self.handle_core_action( + action, + auth_state, + terminal, + app_state, + router, + ).await?; + return Ok(outcome); + } _ => {} } }