working but some functionality is missing now

This commit is contained in:
filipriec
2025-02-28 20:39:24 +01:00
parent 9b290e1ad9
commit 55895cd4c5
4 changed files with 126 additions and 28 deletions

View File

@@ -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]

View File

@@ -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
}
}

View File

@@ -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(

View File

@@ -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;