config toml is now fully split between command mode, read only mode and edit mode
This commit is contained in:
@@ -31,7 +31,9 @@ pub struct ModeKeybindings {
|
||||
pub edit: HashMap<String, Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub command: HashMap<String, Vec<String>>,
|
||||
// Add other fields for standalone global keybindings as needed
|
||||
#[serde(default)]
|
||||
pub common: HashMap<String, Vec<String>>,
|
||||
// Store top-level keybindings that aren't in a specific mode section
|
||||
#[serde(flatten)]
|
||||
pub global: HashMap<String, Vec<String>>,
|
||||
}
|
||||
@@ -47,19 +49,25 @@ impl Config {
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Gets an action for a key in Read-Only mode.
|
||||
/// Gets an action for a key in Read-Only mode, also checking common keybindings.
|
||||
pub fn get_read_only_action_for_key(&self, key: KeyCode, modifiers: KeyModifiers) -> Option<&str> {
|
||||
self.get_action_for_key_in_mode(&self.keybindings.read_only, key, modifiers)
|
||||
.or_else(|| self.get_action_for_key_in_mode(&self.keybindings.common, key, modifiers))
|
||||
.or_else(|| self.get_action_for_key_in_mode(&self.keybindings.global, key, modifiers))
|
||||
}
|
||||
|
||||
/// Gets an action for a key in Edit mode.
|
||||
/// Gets an action for a key in Edit mode, also checking common keybindings.
|
||||
pub fn get_edit_action_for_key(&self, key: KeyCode, modifiers: KeyModifiers) -> Option<&str> {
|
||||
self.get_action_for_key_in_mode(&self.keybindings.edit, key, modifiers)
|
||||
.or_else(|| self.get_action_for_key_in_mode(&self.keybindings.common, key, modifiers))
|
||||
.or_else(|| self.get_action_for_key_in_mode(&self.keybindings.global, key, modifiers))
|
||||
}
|
||||
|
||||
/// Gets an action for a key in Command mode.
|
||||
/// Gets an action for a key in Command mode, also checking common keybindings.
|
||||
pub fn get_command_action_for_key(&self, key: KeyCode, modifiers: KeyModifiers) -> Option<&str> {
|
||||
self.get_action_for_key_in_mode(&self.keybindings.command, key, modifiers)
|
||||
.or_else(|| self.get_action_for_key_in_mode(&self.keybindings.common, key, modifiers))
|
||||
.or_else(|| self.get_action_for_key_in_mode(&self.keybindings.global, key, modifiers))
|
||||
}
|
||||
|
||||
/// Helper function to get an action for a key in a specific mode.
|
||||
@@ -98,8 +106,7 @@ impl Config {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Check if this sequence matches any binding across all modes.
|
||||
// First check read_only mode
|
||||
// Check if this sequence matches any binding in the mode-specific sections.
|
||||
for (action, bindings) in &self.keybindings.read_only {
|
||||
for binding in bindings {
|
||||
if binding == &sequence_str {
|
||||
@@ -107,7 +114,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then check edit mode
|
||||
|
||||
for (action, bindings) in &self.keybindings.edit {
|
||||
for binding in bindings {
|
||||
if binding == &sequence_str {
|
||||
@@ -115,7 +122,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then check command mode
|
||||
|
||||
for (action, bindings) in &self.keybindings.command {
|
||||
for binding in bindings {
|
||||
if binding == &sequence_str {
|
||||
@@ -123,6 +130,16 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check common keybindings
|
||||
for (action, bindings) in &self.keybindings.common {
|
||||
for binding in bindings {
|
||||
if binding == &sequence_str {
|
||||
return Some(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally check global bindings
|
||||
for (action, bindings) in &self.keybindings.global {
|
||||
for binding in bindings {
|
||||
@@ -150,6 +167,10 @@ impl Config {
|
||||
"down" => key == KeyCode::Down,
|
||||
"esc" => key == KeyCode::Esc,
|
||||
"enter" => key == KeyCode::Enter,
|
||||
"delete" => key == KeyCode::Delete,
|
||||
"backspace" => key == KeyCode::Backspace,
|
||||
"tab" => key == KeyCode::Tab,
|
||||
"backtab" => key == KeyCode::BackTab,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
@@ -169,6 +190,10 @@ impl Config {
|
||||
"down" => expected_key = Some(KeyCode::Down),
|
||||
"esc" => expected_key = Some(KeyCode::Esc),
|
||||
"enter" => expected_key = Some(KeyCode::Enter),
|
||||
"delete" => expected_key = Some(KeyCode::Delete),
|
||||
"backspace" => expected_key = Some(KeyCode::Backspace),
|
||||
"tab" => expected_key = Some(KeyCode::Tab),
|
||||
"backtab" => expected_key = Some(KeyCode::BackTab),
|
||||
":" => expected_key = Some(KeyCode::Char(':')),
|
||||
part => {
|
||||
if part.len() == 1 {
|
||||
@@ -184,6 +209,7 @@ impl Config {
|
||||
|
||||
/// Gets an action for a command string.
|
||||
pub fn get_action_for_command(&self, command: &str) -> Option<&str> {
|
||||
// First check command mode bindings
|
||||
for (action, bindings) in &self.keybindings.command {
|
||||
for binding in bindings {
|
||||
if binding.starts_with(':') && binding.trim_start_matches(':') == command {
|
||||
@@ -191,6 +217,25 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then check common bindings
|
||||
for (action, bindings) in &self.keybindings.common {
|
||||
for binding in bindings {
|
||||
if binding.starts_with(':') && binding.trim_start_matches(':') == command {
|
||||
return Some(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally check global bindings
|
||||
for (action, bindings) in &self.keybindings.global {
|
||||
for binding in bindings {
|
||||
if binding.starts_with(':') && binding.trim_start_matches(':') == command {
|
||||
return Some(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
@@ -263,7 +308,7 @@ impl Config {
|
||||
key == KeyCode::Backspace && modifiers.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Checks if a key is bound to a specific action.
|
||||
pub fn has_key_for_action(&self, action: &str, key_char: char) -> bool {
|
||||
// Check all mode-specific keybindings for the action
|
||||
@@ -272,25 +317,31 @@ impl Config {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let Some(bindings) = self.keybindings.edit.get(action) {
|
||||
if bindings.iter().any(|binding| binding == &key_char.to_string()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let Some(bindings) = self.keybindings.command.get(action) {
|
||||
if bindings.iter().any(|binding| binding == &key_char.to_string()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let Some(bindings) = self.keybindings.common.get(action) {
|
||||
if bindings.iter().any(|binding| binding == &key_char.to_string()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(bindings) = self.keybindings.global.get(action) {
|
||||
if bindings.iter().any(|binding| binding == &key_char.to_string()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
@@ -317,17 +368,22 @@ impl Config {
|
||||
if let Some(action) = self.check_bindings_for_sequence(&self.keybindings.read_only, &sequence_str, &sequence_plus, sequence) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
|
||||
// Then check edit mode
|
||||
if let Some(action) = self.check_bindings_for_sequence(&self.keybindings.edit, &sequence_str, &sequence_plus, sequence) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
|
||||
// Then check command mode
|
||||
if let Some(action) = self.check_bindings_for_sequence(&self.keybindings.command, &sequence_str, &sequence_plus, sequence) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
|
||||
// Then check common keybindings
|
||||
if let Some(action) = self.check_bindings_for_sequence(&self.keybindings.common, &sequence_str, &sequence_plus, sequence) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
// Finally check global bindings
|
||||
if let Some(action) = self.check_bindings_for_sequence(&self.keybindings.global, &sequence_str, &sequence_plus, sequence) {
|
||||
return Some(action);
|
||||
@@ -335,13 +391,13 @@ impl Config {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
/// Helper method to check a specific mode's bindings against a key sequence
|
||||
fn check_bindings_for_sequence<'a>(
|
||||
&self,
|
||||
mode_bindings: &'a HashMap<String, Vec<String>>,
|
||||
sequence_str: &str,
|
||||
sequence_plus: &str,
|
||||
&self,
|
||||
mode_bindings: &'a HashMap<String, Vec<String>>,
|
||||
sequence_str: &str,
|
||||
sequence_plus: &str,
|
||||
sequence: &[KeyCode]
|
||||
) -> Option<&'a str> {
|
||||
for (action, bindings) in mode_bindings {
|
||||
@@ -392,22 +448,26 @@ impl Config {
|
||||
if self.is_prefix_in_mode(&self.keybindings.read_only, &sequence_str, sequence) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if self.is_prefix_in_mode(&self.keybindings.edit, &sequence_str, sequence) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if self.is_prefix_in_mode(&self.keybindings.command, &sequence_str, sequence) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if self.is_prefix_in_mode(&self.keybindings.common, &sequence_str, sequence) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.is_prefix_in_mode(&self.keybindings.global, &sequence_str, sequence) {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
/// Helper method to check if a sequence is a prefix in a specific mode
|
||||
fn is_prefix_in_mode(
|
||||
&self,
|
||||
|
||||
Reference in New Issue
Block a user