// src/functions/modes/navigation/add_logic_nav.rs use crate::config::binds::config::{Config, EditorKeybindingMode}; use crate::state::{ app::state::AppState, pages::add_logic::{AddLogicFocus, AddLogicState}, app::buffer::AppView, app::buffer::BufferState, }; use crossterm::event::{KeyEvent, KeyCode, KeyModifiers}; use crate::services::GrpcClient; use tokio::sync::mpsc; use anyhow::Result; use crate::components::common::text_editor::TextEditor; pub type SaveLogicResultSender = mpsc::Sender>; pub fn handle_add_logic_navigation( key_event: KeyEvent, config: &Config, app_state: &mut AppState, add_logic_state: &mut AddLogicState, is_edit_mode: &mut bool, buffer_state: &mut BufferState, grpc_client: GrpcClient, save_logic_sender: SaveLogicResultSender, command_message: &mut String, ) -> bool { // === FULLSCREEN SCRIPT EDITING - COMPLETE ISOLATION === if add_logic_state.current_focus == AddLogicFocus::InsideScriptContent { let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut(); // Handle ONLY Escape to exit fullscreen mode if key_event.code == KeyCode::Esc && key_event.modifiers == KeyModifiers::NONE { match add_logic_state.editor_keybinding_mode { EditorKeybindingMode::Vim => { if *is_edit_mode { // First escape: try to go to Vim Normal mode TextEditor::handle_input( &mut editor_borrow, key_event, &add_logic_state.editor_keybinding_mode, &mut add_logic_state.vim_state, ); if TextEditor::is_vim_normal_mode(&add_logic_state.vim_state) { *is_edit_mode = false; *command_message = "VIM: Normal Mode. Esc again to exit script.".to_string(); } } else { // Second escape: exit fullscreen add_logic_state.current_focus = AddLogicFocus::ScriptContentPreview; app_state.ui.focus_outside_canvas = true; *is_edit_mode = false; *command_message = "Exited script editing.".to_string(); } } _ => { if *is_edit_mode { *is_edit_mode = false; *command_message = "Exited script edit. Esc again to exit script.".to_string(); } else { // Exit fullscreen add_logic_state.current_focus = AddLogicFocus::ScriptContentPreview; app_state.ui.focus_outside_canvas = true; *is_edit_mode = false; *command_message = "Exited script editing.".to_string(); } } } return true; } // ALL OTHER KEYS: Pass directly to textarea without any interference let changed = TextEditor::handle_input( &mut editor_borrow, key_event, &add_logic_state.editor_keybinding_mode, &mut add_logic_state.vim_state, ); if changed { add_logic_state.has_unsaved_changes = true; } // Update edit mode status for Vim if add_logic_state.editor_keybinding_mode == EditorKeybindingMode::Vim { *is_edit_mode = !TextEditor::is_vim_normal_mode(&add_logic_state.vim_state); } return true; // Always consume the event in fullscreen mode } // === END FULLSCREEN ISOLATION === // Regular navigation logic for non-fullscreen elements let action = config.get_general_action(key_event.code, key_event.modifiers); let current_focus = add_logic_state.current_focus; let mut handled = true; let mut new_focus = current_focus; match action.as_deref() { Some("exit_table_scroll") => { // This shouldn't happen since we handle InsideScriptContent above handled = false; } Some("move_up") => { match current_focus { AddLogicFocus::InputLogicName => { // Stay at top } AddLogicFocus::InputTargetColumn => new_focus = AddLogicFocus::InputLogicName, AddLogicFocus::InputDescription => new_focus = AddLogicFocus::InputTargetColumn, AddLogicFocus::ScriptContentPreview => new_focus = AddLogicFocus::InputDescription, AddLogicFocus::SaveButton => new_focus = AddLogicFocus::ScriptContentPreview, AddLogicFocus::CancelButton => new_focus = AddLogicFocus::SaveButton, _ => handled = false, } } Some("move_down") => { match current_focus { AddLogicFocus::InputLogicName => new_focus = AddLogicFocus::InputTargetColumn, AddLogicFocus::InputTargetColumn => new_focus = AddLogicFocus::InputDescription, AddLogicFocus::InputDescription => { add_logic_state.last_canvas_field = 2; new_focus = AddLogicFocus::ScriptContentPreview; }, AddLogicFocus::ScriptContentPreview => new_focus = AddLogicFocus::SaveButton, AddLogicFocus::SaveButton => new_focus = AddLogicFocus::CancelButton, AddLogicFocus::CancelButton => { // Stay at bottom } _ => handled = false, } } Some("next_option") => { match current_focus { AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription => { new_focus = AddLogicFocus::ScriptContentPreview; } AddLogicFocus::ScriptContentPreview => new_focus = AddLogicFocus::SaveButton, AddLogicFocus::SaveButton => new_focus = AddLogicFocus::CancelButton, AddLogicFocus::CancelButton => { /* Stay at last */ } _ => handled = false, } } Some("previous_option") => { match current_focus { AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription => { /* Stay at first */ } AddLogicFocus::ScriptContentPreview => new_focus = AddLogicFocus::InputDescription, AddLogicFocus::SaveButton => new_focus = AddLogicFocus::ScriptContentPreview, AddLogicFocus::CancelButton => new_focus = AddLogicFocus::SaveButton, _ => handled = false, } } Some("next_field") => { new_focus = match current_focus { AddLogicFocus::InputLogicName => AddLogicFocus::InputTargetColumn, AddLogicFocus::InputTargetColumn => AddLogicFocus::InputDescription, AddLogicFocus::InputDescription => AddLogicFocus::ScriptContentPreview, AddLogicFocus::ScriptContentPreview => AddLogicFocus::SaveButton, AddLogicFocus::SaveButton => AddLogicFocus::CancelButton, AddLogicFocus::CancelButton => AddLogicFocus::InputLogicName, _ => current_focus, }; } Some("prev_field") => { new_focus = match current_focus { AddLogicFocus::InputLogicName => AddLogicFocus::CancelButton, AddLogicFocus::InputTargetColumn => AddLogicFocus::InputLogicName, AddLogicFocus::InputDescription => AddLogicFocus::InputTargetColumn, AddLogicFocus::ScriptContentPreview => AddLogicFocus::InputDescription, AddLogicFocus::SaveButton => AddLogicFocus::ScriptContentPreview, AddLogicFocus::CancelButton => AddLogicFocus::SaveButton, _ => current_focus, }; } Some("select") => { match current_focus { AddLogicFocus::ScriptContentPreview => { new_focus = AddLogicFocus::InsideScriptContent; *is_edit_mode = false; // Start in preview mode app_state.ui.focus_outside_canvas = false; // Script is like canvas let mode_hint = match add_logic_state.editor_keybinding_mode { EditorKeybindingMode::Vim => "VIM mode - 'i'/'a'/'o' to edit", _ => "Enter/Ctrl+E to edit", }; *command_message = format!("Fullscreen script editing. {} or Esc to exit.", mode_hint); } AddLogicFocus::SaveButton => { *command_message = "Save logic action".to_string(); } AddLogicFocus::CancelButton => { buffer_state.update_history(AppView::Admin); app_state.ui.show_add_logic = false; *command_message = "Cancelled Add Logic".to_string(); *is_edit_mode = false; } AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription => { *is_edit_mode = !*is_edit_mode; *command_message = format!("Field edit mode: {}", if *is_edit_mode { "ON" } else { "OFF" }); } _ => handled = false, } } Some("toggle_edit_mode") => { match current_focus { AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription => { *is_edit_mode = !*is_edit_mode; *command_message = format!("Canvas field edit mode: {}", if *is_edit_mode { "ON" } else { "OFF" }); } _ => { *command_message = "Cannot toggle edit mode here.".to_string(); } } } _ => handled = false, } if handled && current_focus != new_focus { add_logic_state.current_focus = new_focus; // Set edit mode and canvas focus based on new focus let new_is_canvas_input_focus = matches!(new_focus, AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription ); if new_is_canvas_input_focus { // Entering canvas - start in readonly mode *is_edit_mode = false; app_state.ui.focus_outside_canvas = false; } else { // Outside canvas app_state.ui.focus_outside_canvas = true; if matches!(new_focus, AddLogicFocus::ScriptContentPreview) { *is_edit_mode = false; } } } handled }