working but some functionality is missing now
This commit is contained in:
@@ -6,6 +6,8 @@ quit = [":q", "ctrl+q"]
|
||||
force_quit = [":q!", "ctrl+shift+q"]
|
||||
save_and_quit = [":wq", "ctrl+shift+s"]
|
||||
|
||||
# [keybindings.common]
|
||||
|
||||
# MODE SPECIFIC
|
||||
# READ ONLY MODE
|
||||
[keybindings.read_only]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// client/src/config.rs
|
||||
// client/src/config/config.rs
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
@@ -31,6 +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(flatten)]
|
||||
pub global: HashMap<String, Vec<String>>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -60,12 +63,12 @@ impl Config {
|
||||
}
|
||||
|
||||
/// Helper function to get an action for a key in a specific mode.
|
||||
fn get_action_for_key_in_mode(
|
||||
fn get_action_for_key_in_mode<'a>(
|
||||
&self,
|
||||
mode_bindings: &HashMap<String, Vec<String>>,
|
||||
mode_bindings: &'a HashMap<String, Vec<String>>,
|
||||
key: KeyCode,
|
||||
modifiers: KeyModifiers,
|
||||
) -> Option<&str> {
|
||||
) -> Option<&'a str> {
|
||||
for (action, bindings) in mode_bindings {
|
||||
for binding in bindings {
|
||||
if Self::matches_keybinding(binding, key, modifiers) {
|
||||
@@ -95,7 +98,8 @@ impl Config {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Check if this sequence matches any binding.
|
||||
// Check if this sequence matches any binding across all modes.
|
||||
// First check read_only mode
|
||||
for (action, bindings) in &self.keybindings.read_only {
|
||||
for binding in bindings {
|
||||
if binding == &sequence_str {
|
||||
@@ -103,6 +107,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then check edit mode
|
||||
for (action, bindings) in &self.keybindings.edit {
|
||||
for binding in bindings {
|
||||
if binding == &sequence_str {
|
||||
@@ -110,6 +115,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then check command mode
|
||||
for (action, bindings) in &self.keybindings.command {
|
||||
for binding in bindings {
|
||||
if binding == &sequence_str {
|
||||
@@ -117,6 +123,14 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally check global bindings
|
||||
for (action, bindings) in &self.keybindings.global {
|
||||
for binding in bindings {
|
||||
if binding == &sequence_str {
|
||||
return Some(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@@ -249,15 +263,34 @@ 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 {
|
||||
if let Some(bindings) = self.keybindings.get(action) {
|
||||
for binding in bindings {
|
||||
if binding == &key_char.to_string() {
|
||||
return true;
|
||||
}
|
||||
// Check all mode-specific keybindings for the action
|
||||
if let Some(bindings) = self.keybindings.read_only.get(action) {
|
||||
if bindings.iter().any(|binding| binding == &key_char.to_string()) {
|
||||
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.global.get(action) {
|
||||
if bindings.iter().any(|binding| binding == &key_char.to_string()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
@@ -279,8 +312,39 @@ impl Config {
|
||||
.collect::<Vec<String>>()
|
||||
.join("+");
|
||||
|
||||
// Check for matches in all binding formats
|
||||
for (action, bindings) in &self.keybindings {
|
||||
// Check for matches in all binding formats across all modes
|
||||
// First check read_only mode
|
||||
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);
|
||||
}
|
||||
|
||||
// Finally check global bindings
|
||||
if let Some(action) = self.check_bindings_for_sequence(&self.keybindings.global, &sequence_str, &sequence_plus, sequence) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
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,
|
||||
sequence: &[KeyCode]
|
||||
) -> Option<&'a str> {
|
||||
for (action, bindings) in mode_bindings {
|
||||
for binding in bindings {
|
||||
let normalized_binding = binding.to_lowercase();
|
||||
|
||||
@@ -309,7 +373,6 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
@@ -325,13 +388,39 @@ impl Config {
|
||||
.collect::<Vec<String>>()
|
||||
.join("");
|
||||
|
||||
// Check all bindings to see if our sequence is a prefix
|
||||
for (_, bindings) in &self.keybindings {
|
||||
// Check in each mode if our sequence is a prefix
|
||||
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.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,
|
||||
mode_bindings: &HashMap<String, Vec<String>>,
|
||||
sequence_str: &str,
|
||||
sequence: &[KeyCode]
|
||||
) -> bool {
|
||||
for (_, bindings) in mode_bindings {
|
||||
for binding in bindings {
|
||||
let normalized_binding = binding.to_lowercase();
|
||||
|
||||
// Check standard format
|
||||
if normalized_binding.starts_with(&sequence_str) &&
|
||||
if normalized_binding.starts_with(sequence_str) &&
|
||||
normalized_binding.len() > sequence_str.len() {
|
||||
return true;
|
||||
}
|
||||
@@ -355,7 +444,6 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ impl EventHandler {
|
||||
// Mode transitions between edit mode and read-only mode
|
||||
if self.is_edit_mode {
|
||||
// Check for exiting edit mode
|
||||
if config.get_edit_action_for_key(key.code, key.modifiers) == Some("exit_edit_mode") {
|
||||
if config.is_exit_edit_mode(key.code, key.modifiers) {
|
||||
if form_state.has_unsaved_changes {
|
||||
self.command_message = "Unsaved changes! Use :w to save or :q! to discard".to_string();
|
||||
return Ok((false, self.command_message.clone()));
|
||||
@@ -109,20 +109,26 @@ impl EventHandler {
|
||||
return Ok((false, result));
|
||||
} else {
|
||||
// Check for entering edit mode from read-only mode
|
||||
if config.get_read_only_action_for_key(key.code, key.modifiers) == Some("enter_edit_mode_before") {
|
||||
if config.get_read_only_action_for_key(key.code, key.modifiers) == Some("enter_edit_mode_after") {
|
||||
let current_input = form_state.get_current_input();
|
||||
if !current_input.is_empty() && form_state.current_cursor_pos < current_input.len() {
|
||||
form_state.current_cursor_pos += 1;
|
||||
self.ideal_cursor_column = form_state.current_cursor_pos;
|
||||
}
|
||||
}
|
||||
if config.is_enter_edit_mode_before(key.code, key.modifiers) {
|
||||
self.is_edit_mode = true;
|
||||
self.edit_mode_cooldown = true;
|
||||
self.command_message = "Edit mode".to_string();
|
||||
app_terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?;
|
||||
return Ok((false, self.command_message.clone()));
|
||||
}
|
||||
|
||||
if config.is_enter_edit_mode_after(key.code, key.modifiers) {
|
||||
let current_input = form_state.get_current_input();
|
||||
if !current_input.is_empty() && form_state.current_cursor_pos < current_input.len() {
|
||||
form_state.current_cursor_pos += 1;
|
||||
self.ideal_cursor_column = form_state.current_cursor_pos;
|
||||
}
|
||||
self.is_edit_mode = true;
|
||||
self.edit_mode_cooldown = true;
|
||||
self.command_message = "Edit mode (after cursor)".to_string();
|
||||
app_terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?;
|
||||
return Ok((false, self.command_message.clone()));
|
||||
}
|
||||
|
||||
// Handle read-only mode events
|
||||
return read_only::handle_read_only_event(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// src/modes/handlers/read_only.rs
|
||||
|
||||
use crossterm::event::{KeyEvent};
|
||||
use crate::config::config::Config;
|
||||
use crate::ui::handlers::form::FormState;
|
||||
@@ -24,13 +26,13 @@ pub async fn handle_read_only_event(
|
||||
ideal_cursor_column: &mut usize,
|
||||
) -> Result<(bool, String), Box<dyn std::error::Error>> {
|
||||
// Check for entering Edit mode from Read-Only mode
|
||||
if config.get_read_only_action_for_key(key.code, key.modifiers) == Some("enter_edit_mode_before") {
|
||||
if config.is_enter_edit_mode_before(key.code, key.modifiers) {
|
||||
*edit_mode_cooldown = true;
|
||||
*command_message = "Entering Edit mode".to_string();
|
||||
return Ok((false, command_message.clone()));
|
||||
}
|
||||
|
||||
if config.get_read_only_action_for_key(key.code, key.modifiers) == Some("enter_edit_mode_after") {
|
||||
if config.is_enter_edit_mode_after(key.code, key.modifiers) {
|
||||
let current_input = form_state.get_current_input();
|
||||
if !current_input.is_empty() && form_state.current_cursor_pos < current_input.len() {
|
||||
form_state.current_cursor_pos += 1;
|
||||
|
||||
Reference in New Issue
Block a user