diff --git a/client/src/modes/canvas/read_only.rs b/client/src/modes/canvas/read_only.rs index b158714..163b3b2 100644 --- a/client/src/modes/canvas/read_only.rs +++ b/client/src/modes/canvas/read_only.rs @@ -2,7 +2,6 @@ use crossterm::event::{KeyEvent}; use crate::config::binds::config::Config; -use crate::modes::handlers::read_only::ReadOnlyHandler; use crate::state::pages::form::FormState; use crate::config::binds::key_sequences::KeySequenceTracker; use crate::tui::terminal::grpc_client::GrpcClient; @@ -17,6 +16,7 @@ enum CharType { pub async fn handle_read_only_event( key: KeyEvent, config: &Config, + form_state: &mut FormState, key_sequence_tracker: &mut KeySequenceTracker, current_position: &mut u64, total_count: u64, @@ -24,9 +24,8 @@ pub async fn handle_read_only_event( command_message: &mut String, edit_mode_cooldown: &mut bool, ideal_cursor_column: &mut usize, - handler: &mut dyn ReadOnlyHandler, ) -> Result<(bool, String), Box> { - // Check edit mode transitions first + // Check for entering Edit mode from Read-Only mode if config.is_enter_edit_mode_before(key.code, key.modifiers) { *edit_mode_cooldown = true; *command_message = "Entering Edit mode".to_string(); @@ -34,26 +33,88 @@ pub async fn handle_read_only_event( } if config.is_enter_edit_mode_after(key.code, key.modifiers) { - handler.adjust_cursor_position(ideal_cursor_column); + 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; + *ideal_cursor_column = form_state.current_cursor_pos; + } *edit_mode_cooldown = true; *command_message = "Entering Edit mode (after cursor)".to_string(); return Ok((false, command_message.clone())); } - // Process key bindings - let sequence = key_sequence_tracker.get_sequence(); - let action = config.get_read_only_action_for_key(key.code, key.modifiers) - .or_else(|| config.matches_key_sequence_generalized(&sequence)) - .unwrap_or("unknown"); + // Handle Read-Only mode keybindings + if key.modifiers.is_empty() { + key_sequence_tracker.add_key(key.code); + let sequence = key_sequence_tracker.get_sequence(); - let result = handler.handle_read_only_action( - &action, - grpc_client, - current_position, - total_count - ).await?; + // Try to match the current sequence against Read-Only mode bindings + if let Some(action) = config.matches_key_sequence_generalized(&sequence) { + let result = execute_action( + action, + form_state, + ideal_cursor_column, + key_sequence_tracker, + command_message, + current_position, + total_count, + grpc_client, + ).await?; + key_sequence_tracker.reset(); + return Ok((false, result)); + } - Ok((false, result)) + // Check if this might be a prefix of a longer sequence + if config.is_key_sequence_prefix(&sequence) { + return Ok((false, command_message.clone())); + } + + // Since it's not part of a multi-key sequence, check for a direct action + if sequence.len() == 1 && !config.is_key_sequence_prefix(&sequence) { + if let Some(action) = config.get_read_only_action_for_key(key.code, key.modifiers) { + let result = execute_action( + action, + form_state, + ideal_cursor_column, + key_sequence_tracker, + command_message, + current_position, + total_count, + grpc_client, + ).await?; + key_sequence_tracker.reset(); + return Ok((false, result)); + } + } + } else { + // If modifiers are pressed, check for direct key bindings + key_sequence_tracker.reset(); + + if let Some(action) = config.get_read_only_action_for_key(key.code, key.modifiers) { + let result = execute_action( + action, + form_state, + ideal_cursor_column, + key_sequence_tracker, + command_message, + current_position, + total_count, + grpc_client, + ).await?; + return Ok((false, result)); + } + } + + // Show a helpful message when no binding was found + if !*edit_mode_cooldown { + let default_key = "i".to_string(); + let edit_key = config.keybindings.read_only.get("enter_edit_mode_before") + .and_then(|keys| keys.first()) + .unwrap_or(&default_key); + *command_message = format!("Read-only mode - press {} to edit", edit_key); + } + + Ok((false, command_message.clone())) } async fn execute_action( diff --git a/client/src/modes/handlers.rs b/client/src/modes/handlers.rs index baaef19..8210779 100644 --- a/client/src/modes/handlers.rs +++ b/client/src/modes/handlers.rs @@ -1,4 +1,3 @@ // src/client/modes/handlers.rs pub mod event; pub mod mode_manager; -pub mod read_only; diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index 4df3fab..6e8faac 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -143,6 +143,7 @@ impl EventHandler { return read_only::handle_read_only_event( key, config, + form_state, &mut self.key_sequence_tracker, current_position, total_count, @@ -150,7 +151,6 @@ impl EventHandler { &mut self.command_message, &mut self.edit_mode_cooldown, &mut self.ideal_cursor_column, - form_state, ).await; }, diff --git a/client/src/state/pages/form.rs b/client/src/state/pages/form.rs index b7203e4..0590993 100644 --- a/client/src/state/pages/form.rs +++ b/client/src/state/pages/form.rs @@ -3,7 +3,6 @@ use crate::config::colors::themes::Theme; use ratatui::layout::Rect; use ratatui::Frame; use async_trait::async_trait; -use crate::modes::handlers::read_only::ReadOnlyHandler; use crate::tui::terminal::GrpcClient; pub struct FormState {