diff --git a/client/src/modes/handlers/edit.rs b/client/src/modes/handlers/edit.rs index f7dfcc9..9883303 100644 --- a/client/src/modes/handlers/edit.rs +++ b/client/src/modes/handlers/edit.rs @@ -4,49 +4,16 @@ use crossterm::event::{KeyEvent, KeyCode, KeyModifiers}; use crate::tui::terminal::AppTerminal; use crate::config::config::Config; use crate::ui::handlers::form::FormState; -use crate::modes::handlers::command_mode::handle_command_event; use crate::config::key_sequences::KeySequenceTracker; -pub async fn handle_edit_event( +// This function is called from event.rs and doesn't need to handle mode transitions anymore +pub async fn handle_edit_event_internal( key: KeyEvent, config: &Config, form_state: &mut FormState, - is_edit_mode: &mut bool, - edit_mode_cooldown: &mut bool, ideal_cursor_column: &mut usize, command_message: &mut String, - command_mode: &mut bool, - command_input: &mut String, - app_terminal: &mut AppTerminal, - is_saved: &mut bool, - current_position: &mut u64, - total_count: u64, -) -> Result<(bool, String), Box> { - // Handle command mode if already in it - if *command_mode { - let (should_exit, message, exit_command_mode) = handle_command_event( - key, - config, - form_state, - command_input, - command_message, - app_terminal, - is_saved, - current_position, - total_count, - ).await?; - - if exit_command_mode { - *command_mode = false; - } - - if !message.is_empty() { - return Ok((should_exit, message)); - } - - return Ok((false, "".to_string())); - } - +) -> Result> { // Try to match against configured action mappings first let mut key_sequence_tracker = KeySequenceTracker::new(800); @@ -62,21 +29,18 @@ pub async fn handle_edit_event( let result = execute_edit_action( action, form_state, - is_edit_mode, - edit_mode_cooldown, ideal_cursor_column, command_message, - app_terminal, ).await?; handled_by_config = true; - return Ok((false, result)); + return Ok(result); } // Check if this might be a prefix of a longer sequence if config.is_key_sequence_prefix(&sequence) { // If it's a prefix, wait for more keys handled_by_config = true; - return Ok((false, command_message.clone())); + return Ok(command_message.clone()); } // Since it's not part of a multi-key sequence, check for a direct action @@ -86,14 +50,11 @@ pub async fn handle_edit_event( let result = execute_edit_action( action, form_state, - is_edit_mode, - edit_mode_cooldown, ideal_cursor_column, command_message, - app_terminal, ).await?; handled_by_config = true; - return Ok((false, result)); + return Ok(result); } } } else { @@ -102,14 +63,11 @@ pub async fn handle_edit_event( let result = execute_edit_action( action, form_state, - is_edit_mode, - edit_mode_cooldown, ideal_cursor_column, command_message, - app_terminal, ).await?; handled_by_config = true; - return Ok((false, result)); + return Ok(result); } } @@ -123,8 +81,40 @@ pub async fn handle_edit_event( ); } + Ok(command_message.clone()) +} + +// Original handle_edit_event for backward compatibility - not actually used anymore +// but kept for API compatibility +pub async fn handle_edit_event( + key: KeyEvent, + config: &Config, + form_state: &mut FormState, + is_edit_mode: &mut bool, + edit_mode_cooldown: &mut bool, + ideal_cursor_column: &mut usize, + command_message: &mut String, + command_mode: &mut bool, + command_input: &mut String, + app_terminal: &mut AppTerminal, + is_saved: &mut bool, + current_position: &mut u64, + total_count: u64, +) -> Result<(bool, String), Box> { + // This function should ideally not be called anymore - everything should go through event.rs + // Log a warning that this code path is deprecated + eprintln!("Warning: Deprecated code path in handle_edit_event - use event.rs instead"); + + let result = handle_edit_event_internal( + key, + config, + form_state, + ideal_cursor_column, + command_message, + ).await?; + *edit_mode_cooldown = false; - Ok((false, command_message.clone())) + Ok((false, result)) } // Handle edit-specific key input as a fallback (character input, backspace, delete) @@ -204,11 +194,8 @@ fn handle_edit_specific_input( async fn execute_edit_action( action: &str, form_state: &mut FormState, - is_edit_mode: &mut bool, - edit_mode_cooldown: &mut bool, ideal_cursor_column: &mut usize, command_message: &mut String, - app_terminal: &mut AppTerminal, ) -> Result> { match action { // Navigation actions @@ -268,25 +255,6 @@ async fn execute_edit_action( form_state.current_cursor_pos = (*ideal_cursor_column).min(max_cursor_pos); Ok("Moved to last line".to_string()) } - // Mode actions - "exit_edit_mode" => { - if form_state.has_unsaved_changes { - *command_message = "Unsaved changes! Use :w to save or :q! to discard".to_string(); - return Ok(command_message.clone()); - } - *is_edit_mode = false; - *edit_mode_cooldown = true; - *command_message = "Read-only mode".to_string(); - app_terminal.set_cursor_style(crossterm::cursor::SetCursorStyle::SteadyBlock)?; - - 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 = current_input.len() - 1; - *ideal_cursor_column = form_state.current_cursor_pos; - } - - Ok(command_message.clone()) - } // Word movement actions "move_word_next" => { let current_input = form_state.get_current_input(); diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index 70f704d..e469854 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -42,27 +42,84 @@ impl EventHandler { current_position: &mut u64, ) -> Result<(bool, String), Box> { if let Event::Key(key) = event { - // Handle command mode first + // Handle command mode with highest priority if self.command_mode { - return self.handle_command_mode( - key, config, app_terminal, form_state, - is_saved, current_position, total_count - ).await; + let (should_exit, message, exit_command_mode) = command_mode::handle_command_event( + key, + config, + form_state, + &mut self.command_input, + &mut self.command_message, + app_terminal, + is_saved, + current_position, + total_count, + ).await?; + + if exit_command_mode { + self.command_mode = false; + } + + if !message.is_empty() || should_exit { + return Ok((should_exit, message)); + } + + return Ok((false, String::new())); } - // Handle mode transitions - if self.handle_mode_transitions(key, config, app_terminal, form_state)? { - return Ok((false, self.command_message.clone())); + // Check for entering command mode from any other mode + if config.is_enter_command_mode(key.code, key.modifiers) { + self.command_mode = true; + self.command_input.clear(); + self.command_message.clear(); + return Ok((false, String::new())); } - // Delegate to appropriate mode handler + // Mode transitions between edit mode and read-only mode if self.is_edit_mode { - return self.handle_edit_mode( + // Check for exiting 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())); + } + self.is_edit_mode = false; + self.edit_mode_cooldown = true; + self.command_message = "Read-only mode".to_string(); + app_terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; + + 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 = current_input.len() - 1; + self.ideal_cursor_column = form_state.current_cursor_pos; + } + return Ok((false, self.command_message.clone())); + } + + // Handle edit mode events + return self.handle_edit_mode_internal( key, config, app_terminal, form_state, is_saved, current_position, total_count ).await; } else { - return self.handle_read_only_mode( + // Check for entering edit mode from read-only mode + if config.is_enter_edit_mode(key.code, key.modifiers) { + 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".to_string(); + app_terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?; + return Ok((false, self.command_message.clone())); + } + + // Handle read-only mode events + return self.handle_read_only_mode_internal( key, config, app_terminal, form_state, current_position, total_count ).await; @@ -73,7 +130,7 @@ impl EventHandler { Ok((false, self.command_message.clone())) } - async fn handle_command_mode( + async fn handle_edit_mode_internal( &mut self, key: KeyEvent, config: &Config, @@ -83,120 +140,21 @@ impl EventHandler { current_position: &mut u64, total_count: u64, ) -> Result<(bool, String), Box> { - // Check for exit_command_mode binding first - if config.is_exit_command_mode(key.code, key.modifiers) { - self.command_mode = false; - self.command_input.clear(); - return Ok((false, String::new())); - } - - // Existing command mode handling - let (should_exit, message, exit_command_mode) = command_mode::handle_command_event( + // We're calling the edit handler, but we know we're not in command mode + // and we've already handled exit_edit_mode transition above + let result = edit::handle_edit_event_internal( key, config, form_state, - &mut self.command_input, - &mut self.command_message, - app_terminal, - is_saved, - current_position, - total_count, - ).await?; - - if exit_command_mode { - self.command_mode = false; - } - - if !message.is_empty() { - return Ok((should_exit, message)); - } - - Ok((false, "".to_string())) - } - - fn handle_mode_transitions( - &mut self, - key: KeyEvent, - config: &Config, - app_terminal: &mut AppTerminal, - form_state: &mut FormState, - ) -> Result> { - // Enter command mode - if !self.is_edit_mode && config.is_enter_command_mode(key.code, key.modifiers) { - self.command_mode = true; - self.command_input.clear(); - self.command_message.clear(); - return Ok(true); - } - - // Enter edit mode - if !self.is_edit_mode && config.is_enter_edit_mode(key.code, key.modifiers) { - 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".to_string(); - app_terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?; - return Ok(true); - } - - // Exit edit mode - if self.is_edit_mode && 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(true); - } - self.is_edit_mode = false; - self.edit_mode_cooldown = true; - self.command_message = "Read-only mode".to_string(); - app_terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; - - 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 = current_input.len() - 1; - self.ideal_cursor_column = form_state.current_cursor_pos; - } - return Ok(true); - } - - Ok(false) - } - - async fn handle_edit_mode( - &mut self, - key: KeyEvent, - config: &Config, - app_terminal: &mut AppTerminal, - form_state: &mut FormState, - is_saved: &mut bool, - current_position: &mut u64, - total_count: u64, - ) -> Result<(bool, String), Box> { - let result = edit::handle_edit_event( - key, - config, - form_state, - &mut self.is_edit_mode, - &mut self.edit_mode_cooldown, &mut self.ideal_cursor_column, &mut self.command_message, - &mut self.command_mode, - &mut self.command_input, - app_terminal, - is_saved, - current_position, - total_count, - ).await; + ).await?; + self.key_sequence_tracker.reset(); - result + Ok((false, result)) } - async fn handle_read_only_mode( + async fn handle_read_only_mode_internal( &mut self, key: KeyEvent, config: &Config,