diff --git a/canvas/examples/canvas_cursor_auto.rs b/canvas/examples/canvas_cursor_auto.rs index ccc9cee..08b7a0c 100644 --- a/canvas/examples/canvas_cursor_auto.rs +++ b/canvas/examples/canvas_cursor_auto.rs @@ -324,23 +324,23 @@ impl AutoCursorFormEditor { result } - fn move_WORD_next(&mut self) { - self.editor.move_WORD_next(); + fn move_big_word_next(&mut self) { + self.editor.move_big_word_next(); self.update_visual_selection(); } - fn move_WORD_prev(&mut self) { - self.editor.move_WORD_prev(); + fn move_big_word_prev(&mut self) { + self.editor.move_big_word_prev(); self.update_visual_selection(); } - fn move_WORD_end(&mut self) { - self.editor.move_WORD_end(); + fn move_big_word_end(&mut self) { + self.editor.move_big_word_end(); self.update_visual_selection(); } - fn move_WORD_end_prev(&mut self) { - self.editor.move_WORD_end_prev(); + fn move_big_word_end_prev(&mut self) { + self.editor.move_big_word_end_prev(); self.update_visual_selection(); } } @@ -564,23 +564,23 @@ fn handle_key_press( } (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('W'), _) => { - editor.move_WORD_next(); + editor.move_big_word_next(); editor.set_debug_message("W: next WORD start".to_string()); editor.clear_command_buffer(); } (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('B'), _) => { - editor.move_WORD_prev(); + editor.move_big_word_prev(); editor.set_debug_message("B: previous WORD start".to_string()); editor.clear_command_buffer(); } (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('E'), _) => { // Check if this is 'gE' command if editor.get_command_buffer() == "g" { - editor.move_WORD_end_prev(); + editor.move_big_word_end_prev(); editor.set_debug_message("gE: previous WORD end".to_string()); editor.clear_command_buffer(); } else { - editor.move_WORD_end(); + editor.move_big_word_end(); editor.set_debug_message("E: WORD end".to_string()); editor.clear_command_buffer(); } diff --git a/canvas/examples/validation_1.rs b/canvas/examples/validation_1.rs index 07d0d5c..5e66f9c 100644 --- a/canvas/examples/validation_1.rs +++ b/canvas/examples/validation_1.rs @@ -241,20 +241,17 @@ impl ValidationFormEditor { if !self.validation_enabled { return; } - if let Some(result) = self.editor.current_field_validation() { - match result { - ValidationResult::Valid => { - self.debug_message = format!("Field {}: ✅ Valid", self.editor.current_field() + 1); - } - ValidationResult::Warning { message } => { - self.debug_message = format!("Field {}: ⚠️ {}", self.editor.current_field() + 1, message); - } - ValidationResult::Error { message } => { - self.debug_message = format!("Field {}: ❌ {}", self.editor.current_field() + 1, message); - } + let result = self.editor.validate_current_field(); + match result { + ValidationResult::Valid => { + self.debug_message = format!("Field {}: ✅ Valid", self.editor.current_field() + 1); + } + ValidationResult::Warning { message } => { + self.debug_message = format!("Field {}: ⚠️ {}", self.editor.current_field() + 1, message); + } + ValidationResult::Error { message } => { + self.debug_message = format!("Field {}: ❌ {}", self.editor.current_field() + 1, message); } - } else { - self.debug_message = format!("Field {}: 🔍 Not validated yet", self.editor.current_field() + 1); } } @@ -283,25 +280,24 @@ impl ValidationFormEditor { if result.is_ok() { self.has_unsaved_changes = true; // Show real-time validation feedback - if let Some(validation_result) = self.editor.current_field_validation() { - match validation_result { - ValidationResult::Valid => { - // Don't spam with valid messages, just show character count if applicable - if let Some(limits) = self.get_current_field_limits() { - let field_index = self.editor.current_field(); - if let Some(status) = limits.status_text( - self.editor.data_provider().field_value(field_index) - ) { - self.debug_message = format!("✏️ {}", status); - } + let validation_result = self.editor.validate_current_field(); + match validation_result { + ValidationResult::Valid => { + // Don't spam with valid messages, just show character count if applicable + if let Some(limits) = self.get_current_field_limits() { + let field_index = self.editor.current_field(); + if let Some(status) = limits.status_text( + self.editor.data_provider().field_value(field_index) + ) { + self.debug_message = format!("✏️ {}", status); } } - ValidationResult::Warning { message } => { - self.debug_message = format!("⚠️ {}", message); - } - ValidationResult::Error { message } => { - self.debug_message = format!("❌ {}", message); - } + } + ValidationResult::Warning { message } => { + self.debug_message = format!("⚠️ {}", message); + } + ValidationResult::Error { message } => { + self.debug_message = format!("❌ {}", message); } } } diff --git a/canvas/examples/validation_2.rs b/canvas/examples/validation_2.rs index a20078f..1d3653a 100644 --- a/canvas/examples/validation_2.rs +++ b/canvas/examples/validation_2.rs @@ -129,12 +129,11 @@ impl AdvancedPatternFormEditor { fn insert_char(&mut self, ch: char) -> anyhow::Result<()> { let result = self.editor.insert_char(ch); if result.is_ok() { - if let Some(validation_result) = self.editor.current_field_validation() { - match validation_result { - ValidationResult::Valid => { self.debug_message = "✅ Character accepted".to_string(); } - ValidationResult::Warning { message } => { self.debug_message = format!("⚠️ Warning: {}", message); } - ValidationResult::Error { message } => { self.debug_message = format!("❌ Pattern violation: {}", message); } - } + let validation_result = self.editor.validate_current_field(); + match validation_result { + ValidationResult::Valid => { self.debug_message = "✅ Character accepted".to_string(); } + ValidationResult::Warning { message } => { self.debug_message = format!("⚠️ Warning: {}", message); } + ValidationResult::Error { message } => { self.debug_message = format!("❌ Pattern violation: {}", message); } } } Ok(result?) @@ -183,12 +182,11 @@ impl AdvancedPatternFormEditor { fn update_field_validation_status(&mut self) { if !self.validation_enabled { return; } - if let Some(result) = self.editor.current_field_validation() { - match result { - ValidationResult::Valid => { self.debug_message = format!("Field {}: ✅ Pattern valid", self.editor.current_field() + 1); } - ValidationResult::Warning { message } => { self.debug_message = format!("Field {}: ⚠️ {}", self.editor.current_field() + 1, message); } - ValidationResult::Error { message } => { self.debug_message = format!("Field {}: ❌ {}", self.editor.current_field() + 1, message); } - } + let result = self.editor.validate_current_field(); + match result { + ValidationResult::Valid => { self.debug_message = format!("Field {}: ✅ Pattern valid", self.editor.current_field() + 1); } + ValidationResult::Warning { message } => { self.debug_message = format!("Field {}: ⚠️ {}", self.editor.current_field() + 1, message); } + ValidationResult::Error { message } => { self.debug_message = format!("Field {}: ❌ {}", self.editor.current_field() + 1, message); } } } diff --git a/canvas/src/canvas/actions/movement/mod.rs b/canvas/src/canvas/actions/movement/mod.rs index 0c0810e..8f17cfb 100644 --- a/canvas/src/canvas/actions/movement/mod.rs +++ b/canvas/src/canvas/actions/movement/mod.rs @@ -7,10 +7,10 @@ pub mod char; // Re-export commonly used functions pub use word::{ find_next_word_start, find_word_end, find_prev_word_start, find_prev_word_end, - find_next_WORD_start, find_prev_WORD_start, find_WORD_end, find_prev_WORD_end, + find_next_big_word_start, find_prev_big_word_start, find_big_word_end, find_prev_big_word_end, // Add these new exports: find_last_word_start_in_field, find_last_word_end_in_field, - find_last_WORD_start_in_field, find_last_WORD_end_in_field, + find_last_big_word_start_in_field, find_last_big_word_end_in_field, }; pub use line::{line_start_position, line_end_position, safe_cursor_position}; pub use char::{move_left, move_right, is_valid_cursor_position, clamp_cursor_position}; diff --git a/canvas/src/canvas/actions/movement/word.rs b/canvas/src/canvas/actions/movement/word.rs index a73c3a8..80e01b7 100644 --- a/canvas/src/canvas/actions/movement/word.rs +++ b/canvas/src/canvas/actions/movement/word.rs @@ -161,8 +161,8 @@ pub fn find_prev_word_end(text: &str, current_pos: usize) -> usize { 0 } -/// Find the start of the next WORD (whitespace-separated) -pub fn find_next_WORD_start(text: &str, current_pos: usize) -> usize { +/// Find the start of the next big_word (whitespace-separated) +pub fn find_next_big_word_start(text: &str, current_pos: usize) -> usize { let chars: Vec = text.chars().collect(); if chars.is_empty() || current_pos >= chars.len() { return text.chars().count(); @@ -170,12 +170,12 @@ pub fn find_next_WORD_start(text: &str, current_pos: usize) -> usize { let mut pos = current_pos; - // If we're on non-whitespace, skip to end of current WORD + // If we're on non-whitespace, skip to end of current big_word while pos < chars.len() && !chars[pos].is_whitespace() { pos += 1; } - // Skip whitespace to find start of next WORD + // Skip whitespace to find start of next big_word while pos < chars.len() && chars[pos].is_whitespace() { pos += 1; } @@ -183,8 +183,8 @@ pub fn find_next_WORD_start(text: &str, current_pos: usize) -> usize { pos } -/// Find the start of the previous WORD (whitespace-separated) -pub fn find_prev_WORD_start(text: &str, current_pos: usize) -> usize { +/// Find the start of the previous big_word (whitespace-separated) +pub fn find_prev_big_word_start(text: &str, current_pos: usize) -> usize { let chars: Vec = text.chars().collect(); if chars.is_empty() || current_pos == 0 { return 0; @@ -197,7 +197,7 @@ pub fn find_prev_WORD_start(text: &str, current_pos: usize) -> usize { pos -= 1; } - // Find start of current WORD by going back while non-whitespace + // Find start of current big_word by going back while non-whitespace while pos > 0 && !chars[pos - 1].is_whitespace() { pos -= 1; } @@ -205,8 +205,8 @@ pub fn find_prev_WORD_start(text: &str, current_pos: usize) -> usize { pos } -/// Find the end of the current/next WORD (whitespace-separated) -pub fn find_WORD_end(text: &str, current_pos: usize) -> usize { +/// Find the end of the current/next big_word (whitespace-separated) +pub fn find_big_word_end(text: &str, current_pos: usize) -> usize { let chars: Vec = text.chars().collect(); if chars.is_empty() { return 0; @@ -214,7 +214,7 @@ pub fn find_WORD_end(text: &str, current_pos: usize) -> usize { let mut pos = current_pos; - // If we're on whitespace, skip to start of next WORD + // If we're on whitespace, skip to start of next big_word while pos < chars.len() && chars[pos].is_whitespace() { pos += 1; } @@ -224,17 +224,17 @@ pub fn find_WORD_end(text: &str, current_pos: usize) -> usize { return chars.len(); } - // Find end of current WORD (last non-whitespace char) + // Find end of current big_word (last non-whitespace char) while pos < chars.len() && !chars[pos].is_whitespace() { pos += 1; } - // Return position of last character in WORD + // Return position of last character in big_word pos.saturating_sub(1) } -/// Find the end of the previous WORD (whitespace-separated) -pub fn find_prev_WORD_end(text: &str, current_pos: usize) -> usize { +/// Find the end of the previous big_word (whitespace-separated) +pub fn find_prev_big_word_end(text: &str, current_pos: usize) -> usize { let chars: Vec = text.chars().collect(); if chars.is_empty() || current_pos == 0 { return 0; @@ -252,17 +252,17 @@ pub fn find_prev_WORD_end(text: &str, current_pos: usize) -> usize { return 0; } - // Skip back to start of current WORD, then forward to end + // Skip back to start of current big_word, then forward to end while pos > 0 && !chars[pos - 1].is_whitespace() { pos -= 1; } - // Now find end of this WORD + // Now find end of this big_word while pos < chars.len() && !chars[pos].is_whitespace() { pos += 1; } - // Return position of last character in WORD + // Return position of last character in big_word pos.saturating_sub(1) } @@ -341,8 +341,8 @@ pub fn find_last_word_end_in_field(text: &str) -> usize { pos } -/// Find the start of the last WORD in a field (for cross-field 'B' movement) -pub fn find_last_WORD_start_in_field(text: &str) -> usize { +/// Find the start of the last big_word in a field (for cross-field 'B' movement) +pub fn find_last_big_word_start_in_field(text: &str) -> usize { if text.is_empty() { return 0; } @@ -365,11 +365,11 @@ pub fn find_last_WORD_start_in_field(text: &str) -> usize { } // Now we're on a non-whitespace character - // Find the start of this WORD by going backwards while chars are non-whitespace + // Find the start of this big_word by going backwards while chars are non-whitespace while pos > 0 { let prev_char = chars[pos - 1]; - // Stop if we hit whitespace (WORD boundary) + // Stop if we hit whitespace (big_word boundary) if prev_char.is_whitespace() { break; } @@ -379,8 +379,8 @@ pub fn find_last_WORD_start_in_field(text: &str) -> usize { pos } -/// Find the end of the last WORD in a field (for cross-field 'gE' movement) -pub fn find_last_WORD_end_in_field(text: &str) -> usize { +/// Find the end of the last big_word in a field (for cross-field 'gE' movement) +pub fn find_last_big_word_end_in_field(text: &str) -> usize { let chars: Vec = text.chars().collect(); if chars.is_empty() { return 0; @@ -398,6 +398,6 @@ pub fn find_last_WORD_end_in_field(text: &str) -> usize { return 0; } - // We're now at the end of the last WORD + // We're now at the end of the last big_word pos } diff --git a/canvas/src/canvas/gui.rs b/canvas/src/canvas/gui.rs index ff57daa..0ee989d 100644 --- a/canvas/src/canvas/gui.rs +++ b/canvas/src/canvas/gui.rs @@ -69,6 +69,7 @@ pub fn render_canvas_with_highlight( let is_edit_mode = matches!(ui_state.mode(), crate::canvas::modes::AppMode::Edit); // Precompute completion for active field + #[cfg(feature = "suggestions")] let active_completion = if ui_state.is_suggestions_active() && ui_state.suggestions.active_field == Some(current_field_idx) { @@ -77,6 +78,9 @@ pub fn render_canvas_with_highlight( None }; + #[cfg(not(feature = "suggestions"))] + let active_completion: Option = None; + render_canvas_fields( f, area, diff --git a/canvas/src/canvas/state.rs b/canvas/src/canvas/state.rs index b93fe0f..8ec1c19 100644 --- a/canvas/src/canvas/state.rs +++ b/canvas/src/canvas/state.rs @@ -14,7 +14,8 @@ pub struct EditorState { // Mode state pub(crate) current_mode: AppMode, - // Suggestions dropdown state + // Suggestions dropdown state (only available with suggestions feature) + #[cfg(feature = "suggestions")] pub(crate) suggestions: SuggestionsUIState, // Selection state (for vim visual mode) @@ -29,6 +30,7 @@ pub struct EditorState { pub(crate) computed: Option, } +#[cfg(feature = "suggestions")] #[derive(Debug, Clone)] pub struct SuggestionsUIState { pub(crate) is_active: bool, @@ -53,6 +55,7 @@ impl EditorState { cursor_pos: 0, ideal_cursor_column: 0, current_mode: AppMode::Edit, + #[cfg(feature = "suggestions")] suggestions: SuggestionsUIState { is_active: false, is_loading: false, @@ -103,11 +106,13 @@ impl EditorState { } /// Check if suggestions dropdown is active (for user's business logic) + #[cfg(feature = "suggestions")] pub fn is_suggestions_active(&self) -> bool { self.suggestions.is_active } /// Check if suggestions dropdown is loading (for user's business logic) + #[cfg(feature = "suggestions")] pub fn is_suggestions_loading(&self) -> bool { self.suggestions.is_loading } @@ -153,6 +158,7 @@ impl EditorState { } /// Explicitly open suggestions — should only be called on Tab + #[cfg(feature = "suggestions")] pub(crate) fn open_suggestions(&mut self, field_index: usize) { self.suggestions.is_active = true; self.suggestions.is_loading = true; @@ -163,6 +169,7 @@ impl EditorState { } /// Explicitly close suggestions — should be called on Esc or field change + #[cfg(feature = "suggestions")] pub(crate) fn close_suggestions(&mut self) { self.suggestions.is_active = false; self.suggestions.is_loading = false; diff --git a/canvas/src/data_provider.rs b/canvas/src/data_provider.rs index c092009..312d324 100644 --- a/canvas/src/data_provider.rs +++ b/canvas/src/data_provider.rs @@ -1,6 +1,7 @@ // src/data_provider.rs //! Simplified user interface - only business data, no UI state +#[cfg(feature = "suggestions")] use anyhow::Result; #[cfg(feature = "suggestions")] use async_trait::async_trait; diff --git a/canvas/src/editor/mode.rs b/canvas/src/editor/mode.rs index fa164ac..94cbe17 100644 --- a/canvas/src/editor/mode.rs +++ b/canvas/src/editor/mode.rs @@ -196,20 +196,20 @@ impl FormEditor { self.move_word_end_prev(); } - pub fn move_WORD_next_with_selection(&mut self) { - self.move_WORD_next(); + pub fn move_big_word_next_with_selection(&mut self) { + self.move_big_word_next(); } - pub fn move_WORD_end_with_selection(&mut self) { - self.move_WORD_end(); + pub fn move_big_word_end_with_selection(&mut self) { + self.move_big_word_end(); } - pub fn move_WORD_prev_with_selection(&mut self) { - self.move_WORD_prev(); + pub fn move_big_word_prev_with_selection(&mut self) { + self.move_big_word_prev(); } - pub fn move_WORD_end_prev_with_selection(&mut self) { - self.move_WORD_end_prev(); + pub fn move_big_word_end_prev_with_selection(&mut self) { + self.move_big_word_end_prev(); } pub fn move_line_start_with_selection(&mut self) { diff --git a/canvas/src/editor/movement.rs b/canvas/src/editor/movement.rs index 22841df..5f76626 100644 --- a/canvas/src/editor/movement.rs +++ b/canvas/src/editor/movement.rs @@ -7,11 +7,7 @@ use crate::canvas::modes::AppMode; use crate::editor::FormEditor; use crate::DataProvider; use crate::canvas::actions::movement::word::{ - find_last_WORD_end_in_field, find_last_WORD_start_in_field, - find_last_word_end_in_field, find_last_word_start_in_field, - find_next_WORD_start, find_next_word_start, find_prev_WORD_end, - find_prev_WORD_start, find_prev_word_end, find_prev_word_start, - find_WORD_end, find_word_end, + find_last_big_word_start_in_field, find_last_word_start_in_field, }; impl FormEditor { @@ -380,7 +376,6 @@ impl FormEditor { return; } - // CHANGE THIS LINE: replace find_prev_word_end_corrected with find_prev_word_end let new_pos = find_prev_word_end(current_text, current_pos); // Only try to cross fields if we didn't move at all (stayed at same position) @@ -413,30 +408,30 @@ impl FormEditor { } } - /// Move to start of next WORD (vim W) - can cross field boundaries - pub fn move_WORD_next(&mut self) { - use crate::canvas::actions::movement::word::find_next_WORD_start; + /// Move to start of next big_word (vim W) - can cross field boundaries + pub fn move_big_word_next(&mut self) { + use crate::canvas::actions::movement::word::find_next_big_word_start; let current_text = self.current_text(); if current_text.is_empty() { // Empty field - try to move to next field if self.move_down().is_ok() { - // Successfully moved to next field, try to find first WORD + // Successfully moved to next field, try to find first big_word let new_text = self.current_text(); if !new_text.is_empty() { - let first_WORD_pos = if new_text.chars().next().map_or(false, |c| !c.is_whitespace()) { + let first_big_word_pos = if new_text.chars().next().map_or(false, |c| !c.is_whitespace()) { // Field starts with non-whitespace, go to position 0 0 } else { - // Field starts with whitespace, find first WORD - find_next_WORD_start(new_text, 0) + // Field starts with whitespace, find first big_word + find_next_big_word_start(new_text, 0) }; let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; let char_len = new_text.chars().count(); let final_pos = if is_edit_mode { - first_WORD_pos.min(char_len) + first_big_word_pos.min(char_len) } else { - first_WORD_pos.min(char_len.saturating_sub(1)) + first_big_word_pos.min(char_len.saturating_sub(1)) }; self.ui_state.cursor_pos = final_pos; self.ui_state.ideal_cursor_column = final_pos; @@ -446,7 +441,7 @@ impl FormEditor { } let current_pos = self.ui_state.cursor_pos; - let new_pos = find_next_WORD_start(current_text, current_pos); + let new_pos = find_next_big_word_start(current_text, current_pos); // Check if we've hit the end of the current field if new_pos >= current_text.chars().count() { @@ -459,20 +454,20 @@ impl FormEditor { self.ui_state.cursor_pos = 0; self.ui_state.ideal_cursor_column = 0; } else { - // Find first WORD in new field - let first_WORD_pos = if new_text.chars().next().map_or(false, |c| !c.is_whitespace()) { + // Find first big_word in new field + let first_big_word_pos = if new_text.chars().next().map_or(false, |c| !c.is_whitespace()) { // Field starts with non-whitespace, go to position 0 0 } else { - // Field starts with whitespace, find first WORD - find_next_WORD_start(new_text, 0) + // Field starts with whitespace, find first big_word + find_next_big_word_start(new_text, 0) }; let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; let char_len = new_text.chars().count(); let final_pos = if is_edit_mode { - first_WORD_pos.min(char_len) + first_big_word_pos.min(char_len) } else { - first_WORD_pos.min(char_len.saturating_sub(1)) + first_big_word_pos.min(char_len.saturating_sub(1)) }; self.ui_state.cursor_pos = final_pos; self.ui_state.ideal_cursor_column = final_pos; @@ -480,7 +475,7 @@ impl FormEditor { } // If move_down() failed, we stay where we are (at end of last field) } else { - // Normal WORD movement within current field + // Normal big_word movement within current field let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; let char_len = current_text.chars().count(); let final_pos = if is_edit_mode { @@ -494,22 +489,22 @@ impl FormEditor { } } - /// Move to start of previous WORD (vim B) - can cross field boundaries - pub fn move_WORD_prev(&mut self) { - use crate::canvas::actions::movement::word::find_prev_WORD_start; + /// Move to start of previous big_word (vim B) - can cross field boundaries + pub fn move_big_word_prev(&mut self) { + use crate::canvas::actions::movement::word::find_prev_big_word_start; let current_text = self.current_text(); if current_text.is_empty() { - // Empty field - try to move to previous field and find last WORD + // Empty field - try to move to previous field and find last big_word let current_field = self.ui_state.current_field; if self.move_up().is_ok() { // Check if we actually moved to a different field if self.ui_state.current_field != current_field { let new_text = self.current_text(); if !new_text.is_empty() { - let last_WORD_start = find_last_WORD_start_in_field(new_text); - self.ui_state.cursor_pos = last_WORD_start; - self.ui_state.ideal_cursor_column = last_WORD_start; + let last_big_word_start = find_last_big_word_start_in_field(new_text); + self.ui_state.cursor_pos = last_big_word_start; + self.ui_state.ideal_cursor_column = last_big_word_start; } } } @@ -526,43 +521,43 @@ impl FormEditor { if self.ui_state.current_field != current_field { let new_text = self.current_text(); if !new_text.is_empty() { - let last_WORD_start = find_last_WORD_start_in_field(new_text); - self.ui_state.cursor_pos = last_WORD_start; - self.ui_state.ideal_cursor_column = last_WORD_start; + let last_big_word_start = find_last_big_word_start_in_field(new_text); + self.ui_state.cursor_pos = last_big_word_start; + self.ui_state.ideal_cursor_column = last_big_word_start; } } } return; } - // Try to find previous WORD in current field - let new_pos = find_prev_WORD_start(current_text, current_pos); + // Try to find previous big_word in current field + let new_pos = find_prev_big_word_start(current_text, current_pos); // Check if we actually moved if new_pos < current_pos { - // Normal WORD movement within current field - we found a previous WORD + // Normal big_word movement within current field - we found a previous big_word self.ui_state.cursor_pos = new_pos; self.ui_state.ideal_cursor_column = new_pos; } else { - // We didn't move (probably at start of first WORD), try previous field + // We didn't move (probably at start of first big_word), try previous field let current_field = self.ui_state.current_field; if self.move_up().is_ok() { // Check if we actually moved to a different field if self.ui_state.current_field != current_field { let new_text = self.current_text(); if !new_text.is_empty() { - let last_WORD_start = find_last_WORD_start_in_field(new_text); - self.ui_state.cursor_pos = last_WORD_start; - self.ui_state.ideal_cursor_column = last_WORD_start; + let last_big_word_start = find_last_big_word_start_in_field(new_text); + self.ui_state.cursor_pos = last_big_word_start; + self.ui_state.ideal_cursor_column = last_big_word_start; } } } } } - /// Move to end of current/next WORD (vim E) - can cross field boundaries - pub fn move_WORD_end(&mut self) { - use crate::canvas::actions::movement::word::find_WORD_end; + /// Move to end of current/next big_word (vim E) - can cross field boundaries + pub fn move_big_word_end(&mut self) { + use crate::canvas::actions::movement::word::find_big_word_end; let current_text = self.current_text(); if current_text.is_empty() { @@ -570,14 +565,14 @@ impl FormEditor { if self.move_down().is_ok() { let new_text = self.current_text(); if !new_text.is_empty() { - // Find first WORD end in new field - let first_WORD_end = find_WORD_end(new_text, 0); + // Find first big_word end in new field + let first_big_word_end = find_big_word_end(new_text, 0); let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; let char_len = new_text.chars().count(); let final_pos = if is_edit_mode { - first_WORD_end.min(char_len) + first_big_word_end.min(char_len) } else { - first_WORD_end.min(char_len.saturating_sub(1)) + first_big_word_end.min(char_len.saturating_sub(1)) }; self.ui_state.cursor_pos = final_pos; self.ui_state.ideal_cursor_column = final_pos; @@ -588,12 +583,12 @@ impl FormEditor { let current_pos = self.ui_state.cursor_pos; let char_len = current_text.chars().count(); - let new_pos = find_WORD_end(current_text, current_pos); + let new_pos = find_big_word_end(current_text, current_pos); // Check if we didn't move or hit the end of the field if new_pos == current_pos && current_pos + 1 < char_len { - // Try next character and find WORD end from there - let next_pos = find_WORD_end(current_text, current_pos + 1); + // Try next character and find big_word end from there + let next_pos = find_big_word_end(current_text, current_pos + 1); if next_pos < char_len { let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; let final_pos = if is_edit_mode { @@ -610,23 +605,23 @@ impl FormEditor { // If we're at or near the end of the field, try next field (but don't recurse) if new_pos >= char_len.saturating_sub(1) { if self.move_down().is_ok() { - // Find first WORD end in new field + // Find first big_word end in new field let new_text = self.current_text(); if !new_text.is_empty() { - let first_WORD_end = find_WORD_end(new_text, 0); + let first_big_word_end = find_big_word_end(new_text, 0); let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; let new_char_len = new_text.chars().count(); let final_pos = if is_edit_mode { - first_WORD_end.min(new_char_len) + first_big_word_end.min(new_char_len) } else { - first_WORD_end.min(new_char_len.saturating_sub(1)) + first_big_word_end.min(new_char_len.saturating_sub(1)) }; self.ui_state.cursor_pos = final_pos; self.ui_state.ideal_cursor_column = final_pos; } } } else { - // Normal WORD end movement within current field + // Normal big_word end movement within current field let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; let final_pos = if is_edit_mode { new_pos.min(char_len) @@ -639,23 +634,24 @@ impl FormEditor { } } - /// Move to end of previous WORD (vim gE) - can cross field boundaries - pub fn move_WORD_end_prev(&mut self) { - use crate::canvas::actions::movement::word::{find_prev_WORD_end, find_WORD_end}; + /// Move to end of previous big_word (vim gE) - can cross field boundaries + pub fn move_big_word_end_prev(&mut self) { + use crate::canvas::actions::movement::word::{ + find_prev_big_word_end, find_big_word_end, + }; + let current_text = self.current_text(); if current_text.is_empty() { - // Empty field - try to move to previous field (but don't recurse) let current_field = self.ui_state.current_field; if self.move_up().is_ok() { - // Check if we actually moved to a different field if self.ui_state.current_field != current_field { let new_text = self.current_text(); if !new_text.is_empty() { - // Find end of last WORD in the field - let last_WORD_end = find_last_WORD_end_in_field(new_text); - self.ui_state.cursor_pos = last_WORD_end; - self.ui_state.ideal_cursor_column = last_WORD_end; + // Find first big_word end in new field + let last_big_word_end = find_big_word_end(new_text, 0); + self.ui_state.cursor_pos = last_big_word_end; + self.ui_state.ideal_cursor_column = last_big_word_end; } } } @@ -663,43 +659,23 @@ impl FormEditor { } let current_pos = self.ui_state.cursor_pos; - - // Special case: if we're at position 0, jump to previous field (but don't recurse) - if current_pos == 0 { - let current_field = self.ui_state.current_field; - if self.move_up().is_ok() { - // Check if we actually moved to a different field - if self.ui_state.current_field != current_field { - let new_text = self.current_text(); - if !new_text.is_empty() { - let last_WORD_end = find_last_WORD_end_in_field(new_text); - self.ui_state.cursor_pos = last_WORD_end; - self.ui_state.ideal_cursor_column = last_WORD_end; - } - } - } - return; - } - - let new_pos = find_prev_WORD_end(current_text, current_pos); + let new_pos = find_prev_big_word_end(current_text, current_pos); // Only try to cross fields if we didn't move at all (stayed at same position) if new_pos == current_pos { - // We didn't move within the current field, try previous field let current_field = self.ui_state.current_field; if self.move_up().is_ok() { - // Check if we actually moved to a different field if self.ui_state.current_field != current_field { let new_text = self.current_text(); if !new_text.is_empty() { - let last_WORD_end = find_last_WORD_end_in_field(new_text); - self.ui_state.cursor_pos = last_WORD_end; - self.ui_state.ideal_cursor_column = last_WORD_end; + let last_big_word_end = find_big_word_end(new_text, 0); + self.ui_state.cursor_pos = last_big_word_end; + self.ui_state.ideal_cursor_column = last_big_word_end; } } } } else { - // Normal WORD movement within current field + // Normal big_word movement within current field let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; let char_len = current_text.chars().count(); let final_pos = if is_edit_mode { @@ -707,7 +683,6 @@ impl FormEditor { } else { new_pos.min(char_len.saturating_sub(1)) }; - self.ui_state.cursor_pos = final_pos; self.ui_state.ideal_cursor_column = final_pos; }