diff --git a/canvas/examples/canvas_cursor_auto.rs b/canvas/examples/canvas_cursor_auto.rs index 08b7a0c..35ce8bd 100644 --- a/canvas/examples/canvas_cursor_auto.rs +++ b/canvas/examples/canvas_cursor_auto.rs @@ -38,7 +38,7 @@ use ratatui::{ use canvas::{ canvas::{ gui::render_canvas_default, - modes::{AppMode, ModeManager, HighlightState}, + modes::AppMode, CursorManager, // This import only exists when cursor-style feature is enabled }, DataProvider, FormEditor, @@ -205,7 +205,7 @@ impl AutoCursorFormEditor { self.has_unsaved_changes = true; self.debug_message = "โŒซ Deleted character backward".to_string(); } - Ok(result?) + result } fn delete_forward(&mut self) -> anyhow::Result<()> { @@ -214,7 +214,7 @@ impl AutoCursorFormEditor { self.has_unsaved_changes = true; self.debug_message = "โŒฆ Deleted character forward".to_string(); } - Ok(result?) + result } // === MODE TRANSITIONS WITH AUTOMATIC CURSOR MANAGEMENT === @@ -240,7 +240,7 @@ impl AutoCursorFormEditor { if result.is_ok() { self.has_unsaved_changes = true; } - Ok(result?) + result } // === MANUAL CURSOR OVERRIDE DEMONSTRATION === @@ -429,13 +429,13 @@ fn handle_key_press( (AppMode::ReadOnly, KeyCode::Char('o'), _) => { if let Err(e) = editor.open_line_below() { - editor.set_debug_message(format!("Error opening line below: {}", e)); + editor.set_debug_message(format!("Error opening line below: {e}")); } editor.clear_command_buffer(); } (AppMode::ReadOnly, KeyCode::Char('O'), _) => { if let Err(e) = editor.open_line_above() { - editor.set_debug_message(format!("Error opening line above: {}", e)); + editor.set_debug_message(format!("Error opening line above: {e}")); } editor.clear_command_buffer(); } @@ -694,8 +694,7 @@ fn handle_key_press( editor.set_debug_message("Invalid command sequence".to_string()); } else { editor.set_debug_message(format!( - "Unhandled: {:?} + {:?} in {:?} mode", - key, modifiers, mode + "Unhandled: {key:?} + {modifiers:?} in {mode:?} mode" )); } } @@ -719,7 +718,7 @@ fn run_app( } } Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); + editor.set_debug_message(format!("Error: {e}")); } } } @@ -858,7 +857,7 @@ fn main() -> Result<(), Box> { terminal.show_cursor()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐ŸŽฏ Cursor automatically reset to default!"); diff --git a/canvas/examples/computed_fields.rs b/canvas/examples/computed_fields.rs index 5ec9ea9..2644660 100644 --- a/canvas/examples/computed_fields.rs +++ b/canvas/examples/computed_fields.rs @@ -133,7 +133,7 @@ impl ComputedProvider for InvoiceCalculator { if qty == 0.0 || price == 0.0 { "".to_string() // Show empty if no meaningful calculation } else { - format!("{:.2}", subtotal) + format!("{subtotal:.2}") } } 5 => { @@ -147,7 +147,7 @@ impl ComputedProvider for InvoiceCalculator { if subtotal == 0.0 || tax_rate == 0.0 { "".to_string() } else { - format!("{:.2}", tax_amount) + format!("{tax_amount:.2}") } } 6 => { @@ -162,7 +162,7 @@ impl ComputedProvider for InvoiceCalculator { } else { let tax_amount = subtotal * (tax_rate / 100.0); let total = subtotal + tax_amount; - format!("{:.2}", total) + format!("{total:.2}") } } _ => "".to_string(), @@ -170,7 +170,7 @@ impl ComputedProvider for InvoiceCalculator { } fn handles_field(&self, field_index: usize) -> bool { - matches!(field_index, 4 | 5 | 6) // Subtotal, Tax Amount, Total + matches!(field_index, 4..=6) // Subtotal, Tax Amount, Total } fn field_dependencies(&self, field_index: usize) -> Vec { @@ -244,13 +244,13 @@ impl ComputedFieldsEditor { let mut parts = Vec::new(); if !subtotal.is_empty() { - parts.push(format!("Subtotal=${}", subtotal)); + parts.push(format!("Subtotal=${subtotal}")); } if !tax.is_empty() { - parts.push(format!("Tax=${}", tax)); + parts.push(format!("Tax=${tax}")); } if !total.is_empty() { - parts.push(format!("Total=${}", total)); + parts.push(format!("Total=${total}")); } if !parts.is_empty() { @@ -268,7 +268,7 @@ impl ComputedFieldsEditor { let current_field = self.editor.current_field(); let result = self.editor.insert_char(ch); - if result.is_ok() && matches!(current_field, 1 | 2 | 3) { + if result.is_ok() && matches!(current_field, 1..=3) { self.editor.on_field_changed(&mut self.calculator, current_field); self.update_computed_fields(); } @@ -280,7 +280,7 @@ impl ComputedFieldsEditor { let current_field = self.editor.current_field(); let result = self.editor.delete_backward(); - if result.is_ok() && matches!(current_field, 1 | 2 | 3) { + if result.is_ok() && matches!(current_field, 1..=3) { self.editor.on_field_changed(&mut self.calculator, current_field); self.update_computed_fields(); } @@ -292,7 +292,7 @@ impl ComputedFieldsEditor { let current_field = self.editor.current_field(); let result = self.editor.delete_forward(); - if result.is_ok() && matches!(current_field, 1 | 2 | 3) { + if result.is_ok() && matches!(current_field, 1..=3) { self.editor.on_field_changed(&mut self.calculator, current_field); self.update_computed_fields(); } @@ -312,7 +312,7 @@ impl ComputedFieldsEditor { } else { "editable" }; - self.debug_message = format!("โ†’ {} - {} field", field_name, field_type); + self.debug_message = format!("โ†’ {field_name} - {field_type} field"); } } @@ -328,7 +328,7 @@ impl ComputedFieldsEditor { } else { "editable" }; - self.debug_message = format!("โ† {} - {} field", field_name, field_type); + self.debug_message = format!("โ† {field_name} - {field_type} field"); } } @@ -339,15 +339,14 @@ impl ComputedFieldsEditor { if self.editor.data_provider().is_computed_field(current) || self.is_computed_field(current) { let field_name = self.editor.data_provider().field_name(current); self.debug_message = format!( - "๐Ÿšซ {} is computed (read-only) - Press Tab to move to editable fields", - field_name + "๐Ÿšซ {field_name} is computed (read-only) - Press Tab to move to editable fields" ); return; } self.editor.enter_edit_mode(); let field_name = self.editor.data_provider().field_name(current); - self.debug_message = format!("โœ๏ธ Editing {} - Type to see calculations update", field_name); + self.debug_message = format!("โœ๏ธ Editing {field_name} - Type to see calculations update"); } fn enter_append_mode(&mut self) { @@ -356,22 +355,21 @@ impl ComputedFieldsEditor { if self.editor.data_provider().is_computed_field(current) || self.is_computed_field(current) { let field_name = self.editor.data_provider().field_name(current); self.debug_message = format!( - "๐Ÿšซ {} is computed (read-only) - Press Tab to move to editable fields", - field_name + "๐Ÿšซ {field_name} is computed (read-only) - Press Tab to move to editable fields" ); return; } self.editor.enter_append_mode(); let field_name = self.editor.data_provider().field_name(current); - self.debug_message = format!("โœ๏ธ Appending to {} - Type to see calculations", field_name); + self.debug_message = format!("โœ๏ธ Appending to {field_name} - Type to see calculations"); } fn exit_edit_mode(&mut self) { let current_field = self.editor.current_field(); self.editor.exit_edit_mode(); - if matches!(current_field, 1 | 2 | 3) { + if matches!(current_field, 1..=3) { self.editor.on_field_changed(&mut self.calculator, current_field); self.update_computed_fields(); } @@ -503,7 +501,7 @@ fn run_app( } } Err(e) => { - editor.debug_message = format!("Error: {}", e); + editor.debug_message = format!("Error: {e}"); } } } @@ -615,7 +613,7 @@ fn main() -> Result<(), Box> { terminal.show_cursor()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐Ÿ’ฐ Demo completed! Computed fields should have updated in real-time!"); diff --git a/canvas/examples/full_canvas_demo.rs b/canvas/examples/full_canvas_demo.rs deleted file mode 100644 index c17ec46..0000000 --- a/canvas/examples/full_canvas_demo.rs +++ /dev/null @@ -1,724 +0,0 @@ -// examples/full_canvas_demo.rs -//! Demonstrates the FULL potential of the canvas library using the native API - -use std::io; -use crossterm::{ - cursor::SetCursorStyle, - event::{ - self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers, - }, - execute, - terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, - }, -}; -use ratatui::{ - backend::{Backend, CrosstermBackend}, - layout::{Constraint, Direction, Layout}, - style::{Color, Style}, - text::{Line, Span}, - widgets::{Block, Borders, Paragraph}, - Frame, Terminal, -}; - -use canvas::{ - canvas::{ - gui::render_canvas_default, - modes::{AppMode, ModeManager, HighlightState}, - }, - DataProvider, FormEditor, -}; - -/// Update cursor style based on current AppMode -fn update_cursor_for_mode(mode: AppMode) -> io::Result<()> { - let style = match mode { - AppMode::Edit => SetCursorStyle::SteadyBar, // Thin line for insert mode - AppMode::ReadOnly => SetCursorStyle::SteadyBlock, // Block for normal mode - AppMode::Highlight => SetCursorStyle::BlinkingBlock, // Blinking block for visual mode - AppMode::General => SetCursorStyle::SteadyBlock, // Block for general mode - AppMode::Command => SetCursorStyle::SteadyUnderScore, // Underscore for command mode - }; - - execute!(io::stdout(), style) -} - -// Enhanced FormEditor that adds visual mode and status tracking -struct EnhancedFormEditor { - editor: FormEditor, - highlight_state: HighlightState, - has_unsaved_changes: bool, - debug_message: String, - command_buffer: String, // For multi-key vim commands like "gg" -} - -impl EnhancedFormEditor { - fn new(data_provider: D) -> Self { - Self { - editor: FormEditor::new(data_provider), - highlight_state: HighlightState::Off, - has_unsaved_changes: false, - debug_message: "Full Canvas Demo - All features enabled".to_string(), - command_buffer: String::new(), - } - } - - // === COMMAND BUFFER HANDLING === - - fn clear_command_buffer(&mut self) { - self.command_buffer.clear(); - } - - fn add_to_command_buffer(&mut self, ch: char) { - self.command_buffer.push(ch); - } - - fn get_command_buffer(&self) -> &str { - &self.command_buffer - } - - fn has_pending_command(&self) -> bool { - !self.command_buffer.is_empty() - } - - // === VISUAL/HIGHLIGHT MODE SUPPORT === - - fn enter_visual_mode(&mut self) { - if ModeManager::can_enter_highlight_mode(self.editor.mode()) { - self.editor.set_mode(AppMode::Highlight); - self.highlight_state = HighlightState::Characterwise { - anchor: ( - self.editor.current_field(), - self.editor.cursor_position(), - ), - }; - self.debug_message = "-- VISUAL --".to_string(); - } - } - - fn enter_visual_line_mode(&mut self) { - if ModeManager::can_enter_highlight_mode(self.editor.mode()) { - self.editor.set_mode(AppMode::Highlight); - self.highlight_state = - HighlightState::Linewise { anchor_line: self.editor.current_field() }; - self.debug_message = "-- VISUAL LINE --".to_string(); - } - } - - fn exit_visual_mode(&mut self) { - self.highlight_state = HighlightState::Off; - if self.editor.mode() == AppMode::Highlight { - self.editor.set_mode(AppMode::ReadOnly); - self.debug_message = "Visual mode exited".to_string(); - } - } - - fn update_visual_selection(&mut self) { - if self.editor.mode() == AppMode::Highlight { - match &self.highlight_state { - HighlightState::Characterwise { anchor: _ } => { - self.debug_message = format!( - "Visual selection: char {} in field {}", - self.editor.cursor_position(), - self.editor.current_field() - ); - } - HighlightState::Linewise { anchor_line: _ } => { - self.debug_message = format!( - "Visual line selection: field {}", - self.editor.current_field() - ); - } - _ => {} - } - } - } - - // === ENHANCED MOVEMENT WITH VISUAL UPDATES === - - fn move_left(&mut self) { - self.editor.move_left(); - self.update_visual_selection(); - } - - fn move_right(&mut self) { - self.editor.move_right(); - self.update_visual_selection(); - } - - fn move_up(&mut self) { - self.editor.move_up(); - self.update_visual_selection(); - } - - fn move_down(&mut self) { - self.editor.move_down(); - self.update_visual_selection(); - } - - fn move_word_next(&mut self) { - self.editor.move_word_next(); - self.update_visual_selection(); - } - - fn move_word_prev(&mut self) { - self.editor.move_word_prev(); - self.update_visual_selection(); - } - - fn move_word_end(&mut self) { - self.editor.move_word_end(); - self.update_visual_selection(); - } - - fn move_word_end_prev(&mut self) { - self.editor.move_word_end_prev(); - self.update_visual_selection(); - } - - fn move_line_start(&mut self) { - self.editor.move_line_start(); - self.update_visual_selection(); - } - - fn move_line_end(&mut self) { - self.editor.move_line_end(); - self.update_visual_selection(); - } - - fn move_first_line(&mut self) { - self.editor.move_first_line(); - self.update_visual_selection(); - } - - fn move_last_line(&mut self) { - self.editor.move_last_line(); - self.update_visual_selection(); - } - - fn prev_field(&mut self) { - self.editor.prev_field(); - self.update_visual_selection(); - } - - fn next_field(&mut self) { - self.editor.next_field(); - self.update_visual_selection(); - } - - // === DELETE OPERATIONS === - - fn delete_backward(&mut self) -> anyhow::Result<()> { - let result = self.editor.delete_backward(); - if result.is_ok() { - self.has_unsaved_changes = true; - self.debug_message = "Deleted character backward".to_string(); - } - Ok(result?) - } - - fn delete_forward(&mut self) -> anyhow::Result<()> { - let result = self.editor.delete_forward(); - if result.is_ok() { - self.has_unsaved_changes = true; - self.debug_message = "Deleted character forward".to_string(); - } - Ok(result?) - } - - // === MODE TRANSITIONS === - - fn enter_edit_mode(&mut self) { - self.editor.enter_edit_mode(); - self.debug_message = "-- INSERT --".to_string(); - } - - fn exit_edit_mode(&mut self) { - self.editor.exit_edit_mode(); - self.exit_visual_mode(); - self.debug_message = "".to_string(); - } - - fn insert_char(&mut self, ch: char) -> anyhow::Result<()> { - let result = self.editor.insert_char(ch); - if result.is_ok() { - self.has_unsaved_changes = true; - } - Ok(result?) - } - - // === DELEGATE TO ORIGINAL EDITOR === - - fn current_field(&self) -> usize { - self.editor.current_field() - } - - fn cursor_position(&self) -> usize { - self.editor.cursor_position() - } - - fn mode(&self) -> AppMode { - self.editor.mode() - } - - fn current_text(&self) -> &str { - self.editor.current_text() - } - - fn data_provider(&self) -> &D { - self.editor.data_provider() - } - - fn ui_state(&self) -> &canvas::EditorState { - self.editor.ui_state() - } - - fn set_mode(&mut self, mode: AppMode) { - self.editor.set_mode(mode); - if mode != AppMode::Highlight { - self.exit_visual_mode(); - } - } - - // === STATUS AND DEBUG === - - fn set_debug_message(&mut self, msg: String) { - self.debug_message = msg; - } - - fn debug_message(&self) -> &str { - &self.debug_message - } - - fn highlight_state(&self) -> &HighlightState { - &self.highlight_state - } - - fn has_unsaved_changes(&self) -> bool { - self.has_unsaved_changes - } -} - -// Demo form data with interesting text for word movement -struct FullDemoData { - fields: Vec<(String, String)>, -} - -impl FullDemoData { - fn new() -> Self { - Self { - fields: vec![ - ("Name".to_string(), "John-Paul McDonald".to_string()), - ( - "Email".to_string(), - "user@example-domain.com".to_string(), - ), - ("Phone".to_string(), "+1 (555) 123-4567".to_string()), - ("Address".to_string(), "123 Main St, Apt 4B".to_string()), - ( - "Tags".to_string(), - "urgent,important,follow-up".to_string(), - ), - ( - "Notes".to_string(), - "This is a sample note with multiple words, punctuation! And symbols @#$" - .to_string(), - ), - ], - } - } -} - -impl DataProvider for FullDemoData { - fn field_count(&self) -> usize { - self.fields.len() - } - - fn field_name(&self, index: usize) -> &str { - &self.fields[index].0 - } - - fn field_value(&self, index: usize) -> &str { - &self.fields[index].1 - } - - fn set_field_value(&mut self, index: usize, value: String) { - self.fields[index].1 = value; - } - - fn supports_suggestions(&self, _field_index: usize) -> bool { - false - } - - fn display_value(&self, _index: usize) -> Option<&str> { - None - } -} - -/// Full vim-like key handling using the native FormEditor API -fn handle_key_press( - key: KeyCode, - modifiers: KeyModifiers, - editor: &mut EnhancedFormEditor, -) -> anyhow::Result { - let old_mode = editor.mode(); // Store mode before processing - - // Quit handling - if (key == KeyCode::Char('q') && modifiers.contains(KeyModifiers::CONTROL)) - || (key == KeyCode::Char('c') && modifiers.contains(KeyModifiers::CONTROL)) - || key == KeyCode::F(10) - { - return Ok(false); - } - - match (old_mode, key, modifiers) { - // === MODE TRANSITIONS === - (AppMode::ReadOnly, KeyCode::Char('i'), _) => { - editor.enter_edit_mode(); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly, KeyCode::Char('a'), _) => { - editor.move_right(); // Move after current character - editor.enter_edit_mode(); - editor.set_debug_message("-- INSERT -- (append)".to_string()); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly, KeyCode::Char('A'), _) => { - editor.move_line_end(); - editor.enter_edit_mode(); - editor.set_debug_message("-- INSERT -- (end of line)".to_string()); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly, KeyCode::Char('o'), _) => { - editor.move_line_end(); - editor.enter_edit_mode(); - editor.set_debug_message("-- INSERT -- (open line)".to_string()); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly, KeyCode::Char('v'), _) => { - editor.enter_visual_mode(); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly, KeyCode::Char('V'), _) => { - editor.enter_visual_line_mode(); - editor.clear_command_buffer(); - } - (_, KeyCode::Esc, _) => { - editor.exit_edit_mode(); - editor.clear_command_buffer(); - } - - // === MOVEMENT: VIM-STYLE NAVIGATION === - - // Basic movement (hjkl and arrows) - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('h'), _) - | (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Left, _) => { - editor.move_left(); - editor.set_debug_message("โ† left".to_string()); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('l'), _) - | (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Right, _) => { - editor.move_right(); - editor.set_debug_message("โ†’ right".to_string()); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('j'), _) - | (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Down, _) => { - editor.move_down(); - editor.set_debug_message("โ†“ next field".to_string()); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('k'), _) - | (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Up, _) => { - editor.move_up(); - editor.set_debug_message("โ†‘ previous field".to_string()); - editor.clear_command_buffer(); - } - - // Word movement - Full vim word navigation - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('w'), _) => { - editor.move_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.set_debug_message("b: previous word start".to_string()); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('e'), _) => { - editor.move_word_end(); - editor.set_debug_message("e: word end".to_string()); - editor.clear_command_buffer(); - } - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('W'), _) => { - editor.move_word_end_prev(); - editor.set_debug_message("W: previous word end".to_string()); - editor.clear_command_buffer(); - } - - // Line movement - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('0'), _) - | (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Home, _) => { - editor.move_line_start(); - editor.set_debug_message("0: line start".to_string()); - } - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('$'), _) - | (AppMode::ReadOnly | AppMode::Highlight, KeyCode::End, _) => { - editor.move_line_end(); - editor.set_debug_message("$: line end".to_string()); - } - - // Field/document movement - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('g'), _) => { - if editor.get_command_buffer() == "g" { - // Second 'g' - execute "gg" command - editor.move_first_line(); - editor.set_debug_message("gg: first field".to_string()); - editor.clear_command_buffer(); - } else { - // First 'g' - start command buffer - editor.clear_command_buffer(); - editor.add_to_command_buffer('g'); - editor.set_debug_message("g".to_string()); - } - } - (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('G'), _) => { - editor.move_last_line(); - editor.set_debug_message("G: last field".to_string()); - editor.clear_command_buffer(); - } - - // === EDIT MODE MOVEMENT === - (AppMode::Edit, KeyCode::Left, m) if m.contains(KeyModifiers::CONTROL) => { - editor.move_word_prev(); - editor.set_debug_message("Ctrl+โ† word back".to_string()); - } - (AppMode::Edit, KeyCode::Right, m) if m.contains(KeyModifiers::CONTROL) => { - editor.move_word_next(); - editor.set_debug_message("Ctrl+โ†’ word forward".to_string()); - } - (AppMode::Edit, KeyCode::Left, _) => { - editor.move_left(); - } - (AppMode::Edit, KeyCode::Right, _) => { - editor.move_right(); - } - (AppMode::Edit, KeyCode::Up, _) => { - editor.move_up(); - } - (AppMode::Edit, KeyCode::Down, _) => { - editor.move_down(); - } - (AppMode::Edit, KeyCode::Home, _) => { - editor.move_line_start(); - } - (AppMode::Edit, KeyCode::End, _) => { - editor.move_line_end(); - } - - // === DELETE OPERATIONS === - (AppMode::Edit, KeyCode::Backspace, _) => { - editor.delete_backward()?; - } - (AppMode::Edit, KeyCode::Delete, _) => { - editor.delete_forward()?; - } - - // Delete operations in normal mode (vim x) - (AppMode::ReadOnly, KeyCode::Char('x'), _) => { - editor.delete_forward()?; - editor.set_debug_message("x: deleted character".to_string()); - } - (AppMode::ReadOnly, KeyCode::Char('X'), _) => { - editor.delete_backward()?; - editor.set_debug_message("X: deleted character backward".to_string()); - } - - // === TAB NAVIGATION === - (_, KeyCode::Tab, _) => { - editor.next_field(); - editor.set_debug_message("Tab: next field".to_string()); - } - (_, KeyCode::BackTab, _) => { - editor.prev_field(); - editor.set_debug_message("Shift+Tab: previous field".to_string()); - } - - // === CHARACTER INPUT === - (AppMode::Edit, KeyCode::Char(c), m) if !m.contains(KeyModifiers::CONTROL) => { - editor.insert_char(c)?; - } - - // === DEBUG/INFO COMMANDS === - (AppMode::ReadOnly, KeyCode::Char('?'), _) => { - editor.set_debug_message(format!( - "Field {}/{}, Pos {}, Mode: {:?}", - editor.current_field() + 1, - editor.data_provider().field_count(), - editor.cursor_position(), - editor.mode() - )); - } - - _ => { - // If we have a pending command and this key doesn't complete it, clear the buffer - if editor.has_pending_command() { - editor.clear_command_buffer(); - editor.set_debug_message("Invalid command sequence".to_string()); - } else { - editor.set_debug_message(format!( - "Unhandled: {:?} + {:?} in {:?} mode", - key, modifiers, old_mode - )); - } - } - } - - // Update cursor if mode changed - let new_mode = editor.mode(); - if old_mode != new_mode { - update_cursor_for_mode(new_mode)?; - } - - Ok(true) -} - -fn run_app( - terminal: &mut Terminal, - mut editor: EnhancedFormEditor, -) -> io::Result<()> { - loop { - terminal.draw(|f| ui(f, &editor))?; - - if let Event::Key(key) = event::read()? { - match handle_key_press(key.code, key.modifiers, &mut editor) { - Ok(should_continue) => { - if !should_continue { - break; - } - } - Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); - } - } - } - } - - Ok(()) -} - -fn ui(f: &mut Frame, editor: &EnhancedFormEditor) { - let chunks = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Min(8), Constraint::Length(8)]) - .split(f.area()); - - render_enhanced_canvas(f, chunks[0], editor); - render_status_and_help(f, chunks[1], editor); -} - -fn render_enhanced_canvas( - f: &mut Frame, - area: ratatui::layout::Rect, - editor: &EnhancedFormEditor, -) { - render_canvas_default(f, area, &editor.editor); -} - -fn render_status_and_help( - f: &mut Frame, - area: ratatui::layout::Rect, - editor: &EnhancedFormEditor, -) { - let chunks = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Length(3), Constraint::Length(5)]) - .split(area); - - // Status bar - let mode_text = match editor.mode() { - AppMode::Edit => "INSERT", - AppMode::ReadOnly => "NORMAL", - AppMode::Highlight => match editor.highlight_state() { - HighlightState::Characterwise { .. } => "VISUAL", - HighlightState::Linewise { .. } => "VISUAL LINE", - _ => "VISUAL", - }, - _ => "NORMAL", - }; - - let status_text = if editor.has_pending_command() { - format!("-- {} -- {} [{}]", mode_text, editor.debug_message(), editor.get_command_buffer()) - } else if editor.has_unsaved_changes() { - format!("-- {} -- [Modified] {}", mode_text, editor.debug_message()) - } else { - format!("-- {} -- {}", mode_text, editor.debug_message()) - }; - - let status = Paragraph::new(Line::from(Span::raw(status_text))) - .block(Block::default().borders(Borders::ALL).title("Status")); - - f.render_widget(status, chunks[0]); - - // Help text - let help_text = match editor.mode() { - AppMode::ReadOnly => { - if editor.has_pending_command() { - match editor.get_command_buffer() { - "g" => "Press 'g' again for first field, or any other key to cancel", - _ => "Pending command... (Esc to cancel)" - } - } else { - "Normal: hjkl/arrows=move, w/b/e=words, 0/$=line, gg/G=first/last, i/a/A=insert, v/V=visual, x/X=delete, ?=info" - } - } - AppMode::Edit => { - "Insert: arrows=move, Ctrl+arrows=words, Backspace/Del=delete, Esc=normal, Tab/Shift+Tab=fields" - } - AppMode::Highlight => { - "Visual: hjkl/arrows=extend selection, w/b/e=word selection, Esc=normal" - } - _ => "Press ? for help" - }; - - let help = Paragraph::new(Line::from(Span::raw(help_text))) - .block(Block::default().borders(Borders::ALL).title("Commands")) - .style(Style::default().fg(Color::Gray)); - - f.render_widget(help, chunks[1]); -} - -fn main() -> Result<(), Box> { - enable_raw_mode()?; - let mut stdout = io::stdout(); - execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; - let backend = CrosstermBackend::new(stdout); - let mut terminal = Terminal::new(backend)?; - - let data = FullDemoData::new(); - let mut editor = EnhancedFormEditor::new(data); - editor.set_mode(AppMode::ReadOnly); // Start in normal mode - - // Set initial cursor style - update_cursor_for_mode(editor.mode())?; - - let res = run_app(&mut terminal, editor); - - // Reset cursor style on exit - execute!(io::stdout(), SetCursorStyle::DefaultUserShape)?; - - disable_raw_mode()?; - execute!( - terminal.backend_mut(), - LeaveAlternateScreen, - DisableMouseCapture - )?; - terminal.show_cursor()?; - - if let Err(err) = res { - println!("{:?}", err); - } - - Ok(()) -} diff --git a/canvas/examples/suggestions.rs b/canvas/examples/suggestions.rs index 1c55744..dbe1f5f 100644 --- a/canvas/examples/suggestions.rs +++ b/canvas/examples/suggestions.rs @@ -218,7 +218,7 @@ impl AutoCursorFormEditor { self.has_unsaved_changes = true; self.debug_message = "โŒซ Deleted character backward".to_string(); } - Ok(result?) + result } fn delete_forward(&mut self) -> anyhow::Result<()> { @@ -227,7 +227,7 @@ impl AutoCursorFormEditor { self.has_unsaved_changes = true; self.debug_message = "โŒฆ Deleted character forward".to_string(); } - Ok(result?) + result } // === SUGGESTIONS CONTROL WRAPPERS === @@ -259,7 +259,7 @@ impl AutoCursorFormEditor { if result.is_ok() { self.has_unsaved_changes = true; } - Ok(result?) + result } // === MANUAL CURSOR OVERRIDE DEMONSTRATION === @@ -562,7 +562,7 @@ impl ProductionSuggestionsProvider { query.is_empty() || item.to_lowercase().starts_with(&query_lower) }) .map(|(item, description)| SuggestionItem { - display_text: format!("{} - {}", item, description), + display_text: format!("{item} - {description}"), value_to_store: item.to_string(), }) .collect() @@ -625,7 +625,7 @@ async fn handle_key_press( } } Err(e) => { - editor.set_debug_message(format!("โŒ Suggestion error: {}", e)); + editor.set_debug_message(format!("โŒ Suggestion error: {e}")); } } } @@ -639,7 +639,7 @@ async fn handle_key_press( (_, KeyCode::Enter, _) => { if editor.is_suggestions_active() { if let Some(applied) = editor.apply_suggestion() { - editor.set_debug_message(format!("โœ… Selected: {}", applied)); + editor.set_debug_message(format!("โœ… Selected: {applied}")); } else { editor.set_debug_message("โŒ No suggestion selected".to_string()); } @@ -647,7 +647,7 @@ async fn handle_key_press( editor.next_field(); let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field"); - editor.set_debug_message(format!("Enter: moved to {} field", field_name)); + editor.set_debug_message(format!("Enter: moved to {field_name} field")); } } @@ -726,7 +726,7 @@ async fn handle_key_press( editor.move_down(); let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field"); - editor.set_debug_message(format!("โ†“ moved to {} field", field_name)); + editor.set_debug_message(format!("โ†“ moved to {field_name} field")); editor.clear_command_buffer(); } (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('k'), _) @@ -734,7 +734,7 @@ async fn handle_key_press( editor.move_up(); let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field"); - editor.set_debug_message(format!("โ†‘ moved to {} field", field_name)); + editor.set_debug_message(format!("โ†‘ moved to {field_name} field")); editor.clear_command_buffer(); } @@ -829,7 +829,7 @@ async fn handle_key_press( } } Err(e) => { - editor.set_debug_message(format!("โŒ Suggestion error: {}", e)); + editor.set_debug_message(format!("โŒ Suggestion error: {e}")); } } } @@ -850,7 +850,7 @@ async fn handle_key_press( } } Err(e) => { - editor.set_debug_message(format!("โŒ Suggestion error: {}", e)); + editor.set_debug_message(format!("โŒ Suggestion error: {e}")); } } } @@ -883,7 +883,7 @@ async fn handle_key_press( } } Err(e) => { - editor.set_debug_message(format!("โŒ Suggestion error: {}", e)); + editor.set_debug_message(format!("โŒ Suggestion error: {e}")); } } } @@ -912,8 +912,7 @@ async fn handle_key_press( let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let current_field = field_names.get(editor.current_field()).unwrap_or(&"Field"); editor.set_debug_message(format!( - "{} field - Try: i=insert, Tab=suggestions, j/k=move. Key: {:?}", - current_field, key + "{current_field} field - Try: i=insert, Tab=suggestions, j/k=move. Key: {key:?}" )); } } @@ -939,7 +938,7 @@ async fn run_app( } } Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); + editor.set_debug_message(format!("Error: {e}")); } } } @@ -962,7 +961,7 @@ fn ui(f: &mut Frame, editor: &AutoCursorFormEditor) { f, chunks[0], input_rect, - &canvas::canvas::theme::DefaultCanvasTheme::default(), + &canvas::canvas::theme::DefaultCanvasTheme, editor.inner(), ); } @@ -1110,7 +1109,7 @@ async fn main() -> Result<(), Box> { terminal.show_cursor()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐Ÿš€ Ready to integrate this architecture into your production app!"); diff --git a/canvas/examples/suggestions2.rs b/canvas/examples/suggestions2.rs index eb6f6a5..4bc2f6a 100644 --- a/canvas/examples/suggestions2.rs +++ b/canvas/examples/suggestions2.rs @@ -210,7 +210,7 @@ impl AutoCursorFormEditor { self.has_unsaved_changes = true; self.debug_message = "โŒซ Deleted character backward".to_string(); } - Ok(result?) + result } fn delete_forward(&mut self) -> anyhow::Result<()> { @@ -219,7 +219,7 @@ impl AutoCursorFormEditor { self.has_unsaved_changes = true; self.debug_message = "โŒฆ Deleted character forward".to_string(); } - Ok(result?) + result } // === SUGGESTIONS CONTROL WRAPPERS === @@ -251,7 +251,7 @@ impl AutoCursorFormEditor { if result.is_ok() { self.has_unsaved_changes = true; } - Ok(result?) + result } // === PRODUCTION-READY NON-BLOCKING SUGGESTIONS === @@ -275,7 +275,7 @@ impl AutoCursorFormEditor { if applied { self.editor.update_inline_completion(); if self.editor.suggestions().is_empty() { - self.set_debug_message(format!("๐Ÿ” No matches for '{}'", query)); + self.set_debug_message(format!("๐Ÿ” No matches for '{query}'")); } else { self.set_debug_message(format!("โœจ {} matches for '{}'", self.editor.suggestions().len(), query)); } @@ -283,7 +283,7 @@ impl AutoCursorFormEditor { // If not applied, results were stale (user kept typing) } Err(e) => { - self.set_debug_message(format!("โŒ Suggestion error: {}", e)); + self.set_debug_message(format!("โŒ Suggestion error: {e}")); } } } @@ -574,7 +574,7 @@ impl ProductionSuggestionsProvider { query.is_empty() || item.to_lowercase().starts_with(&query_lower) }) .map(|(item, description)| SuggestionItem { - display_text: format!("{} - {}", item, description), + display_text: format!("{item} - {description}"), value_to_store: item.to_string(), }) .collect() @@ -634,7 +634,7 @@ async fn handle_key_press( (_, KeyCode::Enter, _) => { if editor.is_suggestions_active() { if let Some(applied) = editor.apply_suggestion() { - editor.set_debug_message(format!("โœ… Selected: {}", applied)); + editor.set_debug_message(format!("โœ… Selected: {applied}")); } else { editor.set_debug_message("โŒ No suggestion selected".to_string()); } @@ -642,7 +642,7 @@ async fn handle_key_press( editor.next_field(); let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field"); - editor.set_debug_message(format!("Enter: moved to {} field", field_name)); + editor.set_debug_message(format!("Enter: moved to {field_name} field")); } } @@ -722,7 +722,7 @@ async fn handle_key_press( editor.move_down(); let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field"); - editor.set_debug_message(format!("โ†“ moved to {} field", field_name)); + editor.set_debug_message(format!("โ†“ moved to {field_name} field")); editor.clear_command_buffer(); } (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('k'), _) @@ -730,7 +730,7 @@ async fn handle_key_press( editor.move_up(); let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field"); - editor.set_debug_message(format!("โ†‘ moved to {} field", field_name)); + editor.set_debug_message(format!("โ†‘ moved to {field_name} field")); editor.clear_command_buffer(); } @@ -872,8 +872,7 @@ async fn handle_key_press( let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let current_field = field_names.get(editor.current_field()).unwrap_or(&"Field"); editor.set_debug_message(format!( - "{} field - Try: i=insert, Tab=suggestions, j/k=move. Key: {:?}", - current_field, key + "{current_field} field - Try: i=insert, Tab=suggestions, j/k=move. Key: {key:?}" )); } } @@ -899,7 +898,7 @@ async fn run_app( } } Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); + editor.set_debug_message(format!("Error: {e}")); } } } @@ -922,7 +921,7 @@ fn ui(f: &mut Frame, editor: &AutoCursorFormEditor) { f, chunks[0], input_rect, - &canvas::canvas::theme::DefaultCanvasTheme::default(), + &canvas::canvas::theme::DefaultCanvasTheme, &editor.editor, ); } @@ -1071,7 +1070,7 @@ async fn main() -> Result<(), Box> { terminal.show_cursor()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐Ÿš€ Ready to integrate this architecture into your production app!"); diff --git a/canvas/examples/textarea_normal.rs b/canvas/examples/textarea_normal.rs index be48a7c..a388465 100644 --- a/canvas/examples/textarea_normal.rs +++ b/canvas/examples/textarea_normal.rs @@ -35,7 +35,7 @@ use ratatui::{ }; use canvas::{ - canvas::{modes::AppMode, CursorManager}, + canvas::CursorManager, textarea::{TextArea, TextAreaState}, }; @@ -291,7 +291,7 @@ fn run_app(terminal: &mut Terminal, mut editor: AutoCursorTextAre } } Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); + editor.set_debug_message(format!("Error: {e}")); } } } @@ -389,7 +389,7 @@ fn main() -> Result<(), Box> { terminal.show_cursor()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐ŸŽฏ Cursor automatically reset to default!"); diff --git a/canvas/examples/textarea_vim.rs b/canvas/examples/textarea_vim.rs index 8478a98..d93d266 100644 --- a/canvas/examples/textarea_vim.rs +++ b/canvas/examples/textarea_vim.rs @@ -339,13 +339,13 @@ fn handle_key_press( // Vim o/O commands (AppMode::ReadOnly, KeyCode::Char('o'), _) => { if let Err(e) = editor.open_line_below() { - editor.set_debug_message(format!("Error opening line below: {}", e)); + editor.set_debug_message(format!("Error opening line below: {e}")); } editor.clear_command_buffer(); } (AppMode::ReadOnly, KeyCode::Char('O'), _) => { if let Err(e) = editor.open_line_above() { - editor.set_debug_message(format!("Error opening line above: {}", e)); + editor.set_debug_message(format!("Error opening line above: {e}")); } editor.clear_command_buffer(); } @@ -482,8 +482,7 @@ fn handle_key_press( editor.set_debug_message("Invalid command sequence".to_string()); } else { editor.set_debug_message(format!( - "Unhandled: {:?} + {:?} in {:?} mode", - key, modifiers, mode + "Unhandled: {key:?} + {modifiers:?} in {mode:?} mode" )); } } @@ -507,7 +506,7 @@ fn run_app( } } Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); + editor.set_debug_message(format!("Error: {e}")); } } } @@ -645,7 +644,7 @@ fn main() -> Result<(), Box> { terminal.show_cursor()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐ŸŽฏ Cursor automatically reset to default!"); diff --git a/canvas/examples/validation_1.rs b/canvas/examples/validation_1.rs index 5e66f9c..dc1b2fc 100644 --- a/canvas/examples/validation_1.rs +++ b/canvas/examples/validation_1.rs @@ -141,10 +141,10 @@ impl ValidationFormEditor { self.debug_message = "โœ… Current field is valid!".to_string(); } ValidationResult::Warning { message } => { - self.debug_message = format!("โš ๏ธ Warning: {}", message); + self.debug_message = format!("โš ๏ธ Warning: {message}"); } ValidationResult::Error { message } => { - self.debug_message = format!("โŒ Error: {}", message); + self.debug_message = format!("โŒ Error: {message}"); } } } @@ -189,7 +189,7 @@ impl ValidationFormEditor { Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); - self.debug_message = format!("๐Ÿšซ Field switch blocked: {}", e); + self.debug_message = format!("๐Ÿšซ Field switch blocked: {e}"); } } } @@ -204,7 +204,7 @@ impl ValidationFormEditor { Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); - self.debug_message = format!("๐Ÿšซ Field switch blocked: {}", e); + self.debug_message = format!("๐Ÿšซ Field switch blocked: {e}"); } } } @@ -289,19 +289,19 @@ impl ValidationFormEditor { if let Some(status) = limits.status_text( self.editor.data_provider().field_value(field_index) ) { - self.debug_message = format!("โœ๏ธ {}", status); + self.debug_message = format!("โœ๏ธ {status}"); } } } ValidationResult::Warning { message } => { - self.debug_message = format!("โš ๏ธ {}", message); + self.debug_message = format!("โš ๏ธ {message}"); } ValidationResult::Error { message } => { - self.debug_message = format!("โŒ {}", message); + self.debug_message = format!("โŒ {message}"); } } } - Ok(result?) + result } fn get_current_field_limits(&self) -> Option<&CharacterLimits> { @@ -317,7 +317,7 @@ impl ValidationFormEditor { self.has_unsaved_changes = true; self.debug_message = "โŒซ Deleted character".to_string(); } - Ok(result?) + result } fn delete_forward(&mut self) -> anyhow::Result<()> { @@ -326,7 +326,7 @@ impl ValidationFormEditor { self.has_unsaved_changes = true; self.debug_message = "โŒฆ Deleted character".to_string(); } - Ok(result?) + result } // === DELEGATE TO ORIGINAL EDITOR === @@ -370,7 +370,7 @@ impl ValidationFormEditor { Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); - self.debug_message = format!("๐Ÿšซ Cannot move to next field: {}", e); + self.debug_message = format!("๐Ÿšซ Cannot move to next field: {e}"); } } } @@ -385,7 +385,7 @@ impl ValidationFormEditor { Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); - self.debug_message = format!("๐Ÿšซ Cannot move to previous field: {}", e); + self.debug_message = format!("๐Ÿšซ Cannot move to previous field: {e}"); } } } @@ -644,7 +644,7 @@ fn run_app( } } Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); + editor.set_debug_message(format!("Error: {e}")); } } } @@ -823,7 +823,7 @@ fn main() -> Result<(), Box> { terminal.show_cursor()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐Ÿ” Validation demo completed!"); diff --git a/canvas/examples/validation_2.rs b/canvas/examples/validation_2.rs index 1d3653a..94cf1f9 100644 --- a/canvas/examples/validation_2.rs +++ b/canvas/examples/validation_2.rs @@ -93,14 +93,14 @@ impl AdvancedPatternFormEditor { fn move_up(&mut self) { match self.editor.move_up() { Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; } - Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("๐Ÿšซ Field switch blocked: {}", e); } + Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("๐Ÿšซ Field switch blocked: {e}"); } } } fn move_down(&mut self) { match self.editor.move_down() { Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; } - Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("๐Ÿšซ Field switch blocked: {}", e); } + Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("๐Ÿšซ Field switch blocked: {e}"); } } } @@ -132,23 +132,23 @@ impl AdvancedPatternFormEditor { 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); } + ValidationResult::Warning { message } => { self.debug_message = format!("โš ๏ธ Warning: {message}"); } + ValidationResult::Error { message } => { self.debug_message = format!("โŒ Pattern violation: {message}"); } } } - Ok(result?) + result } fn delete_backward(&mut self) -> anyhow::Result<()> { let result = self.editor.delete_backward(); if result.is_ok() { self.debug_message = "โŒซ Character deleted".to_string(); } - Ok(result?) + result } fn delete_forward(&mut self) -> anyhow::Result<()> { let result = self.editor.delete_forward(); if result.is_ok() { self.debug_message = "โŒฆ Character deleted".to_string(); } - Ok(result?) + result } // Delegate methods @@ -166,14 +166,14 @@ impl AdvancedPatternFormEditor { fn next_field(&mut self) { match self.editor.next_field() { Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; } - Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("๐Ÿšซ Cannot move to next field: {}", e); } + Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("๐Ÿšซ Cannot move to next field: {e}"); } } } fn prev_field(&mut self) { match self.editor.prev_field() { Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; } - Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("๐Ÿšซ Cannot move to previous field: {}", e); } + Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("๐Ÿšซ Cannot move to previous field: {e}"); } } } @@ -492,7 +492,7 @@ fn run_app( } } Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); + editor.set_debug_message(format!("Error: {e}")); } } } @@ -654,7 +654,7 @@ fn main() -> Result<(), Box> { terminal.show_cursor()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐Ÿš€ Advanced pattern validation demo completed!"); diff --git a/canvas/examples/validation_3.rs b/canvas/examples/validation_3.rs index f0a5106..87d4ff8 100644 --- a/canvas/examples/validation_3.rs +++ b/canvas/examples/validation_3.rs @@ -54,7 +54,6 @@ use canvas::{ }, DataProvider, FormEditor, ValidationConfig, ValidationConfigBuilder, DisplayMask, - validation::mask::MaskDisplayMode, }; // Enhanced FormEditor wrapper for mask demonstration @@ -144,14 +143,14 @@ impl MaskDemoFormEditor { fn move_up(&mut self) { match self.editor.move_up() { Ok(()) => { self.update_field_info(); } - Err(e) => { self.debug_message = format!("๐Ÿšซ Field switch blocked: {}", e); } + Err(e) => { self.debug_message = format!("๐Ÿšซ Field switch blocked: {e}"); } } } fn move_down(&mut self) { match self.editor.move_down() { Ok(()) => { self.update_field_info(); } - Err(e) => { self.debug_message = format!("๐Ÿšซ Field switch blocked: {}", e); } + Err(e) => { self.debug_message = format!("๐Ÿšซ Field switch blocked: {e}"); } } } @@ -170,16 +169,16 @@ impl MaskDemoFormEditor { let raw_pos = self.editor.cursor_position(); let display_pos = self.editor.display_cursor_position(); if raw_pos != display_pos { - self.debug_message = format!("๐Ÿ“ Cursor: Raw pos {} โ†’ Display pos {} (mask active)", raw_pos, display_pos); + self.debug_message = format!("๐Ÿ“ Cursor: Raw pos {raw_pos} โ†’ Display pos {display_pos} (mask active)"); } else { - self.debug_message = format!("๐Ÿ“ Cursor at position {} (no mask offset)", raw_pos); + self.debug_message = format!("๐Ÿ“ Cursor at position {raw_pos} (no mask offset)"); } } } fn update_field_info(&mut self) { let field_name = self.editor.data_provider().field_name(self.editor.current_field()); - self.debug_message = format!("๐Ÿ“ Switched to: {}", field_name); + self.debug_message = format!("๐Ÿ“ Switched to: {field_name}"); } // === MODE TRANSITIONS === @@ -206,12 +205,12 @@ impl MaskDemoFormEditor { if result.is_ok() { let (raw, display, _) = self.get_current_field_info(); if raw != display { - self.debug_message = format!("โœ๏ธ Added '{}': Raw='{}' Display='{}'", ch, raw, display); + self.debug_message = format!("โœ๏ธ Added '{ch}': Raw='{raw}' Display='{display}'"); } else { - self.debug_message = format!("โœ๏ธ Added '{}': '{}'", ch, raw); + self.debug_message = format!("โœ๏ธ Added '{ch}': '{raw}'"); } } - Ok(result?) + result } // === DELETE OPERATIONS === @@ -221,7 +220,7 @@ impl MaskDemoFormEditor { self.debug_message = "โŒซ Character deleted".to_string(); self.update_cursor_info(); } - Ok(result?) + result } fn delete_forward(&mut self) -> anyhow::Result<()> { @@ -230,7 +229,7 @@ impl MaskDemoFormEditor { self.debug_message = "โŒฆ Character deleted".to_string(); self.update_cursor_info(); } - Ok(result?) + result } // === DELEGATE TO ORIGINAL EDITOR === @@ -251,14 +250,14 @@ impl MaskDemoFormEditor { fn next_field(&mut self) { match self.editor.next_field() { Ok(()) => { self.update_field_info(); } - Err(e) => { self.debug_message = format!("๐Ÿšซ Cannot move to next field: {}", e); } + Err(e) => { self.debug_message = format!("๐Ÿšซ Cannot move to next field: {e}"); } } } fn prev_field(&mut self) { match self.editor.prev_field() { Ok(()) => { self.update_field_info(); } - Err(e) => { self.debug_message = format!("๐Ÿšซ Cannot move to previous field: {}", e); } + Err(e) => { self.debug_message = format!("๐Ÿšซ Cannot move to previous field: {e}"); } } } @@ -287,7 +286,7 @@ impl MaskDemoFormEditor { } } - format!("๐ŸŽญ {} MASKS", mask_count) + format!("๐ŸŽญ {mask_count} MASKS") } } @@ -549,7 +548,7 @@ fn run_app( } } Err(e) => { - editor.set_debug_message(format!("Error: {}", e)); + editor.set_debug_message(format!("Error: {e}")); } } } @@ -726,7 +725,7 @@ fn main() -> Result<(), Box> { CursorManager::reset()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐ŸŽญ Display mask demo completed!"); diff --git a/canvas/examples/validation_4.rs b/canvas/examples/validation_4.rs index 66d11ec..0369954 100644 --- a/canvas/examples/validation_4.rs +++ b/canvas/examples/validation_4.rs @@ -97,7 +97,7 @@ impl CustomFormatter for PhoneFormatter { let len = raw.chars().count(); match len { 0 => FormattingResult::success(""), - 1..=3 => FormattingResult::success(format!("({})", raw)), + 1..=3 => FormattingResult::success(format!("({raw})")), 4..=6 => FormattingResult::success(format!("({}) {}", &raw[..3], &raw[3..])), 7..=10 => FormattingResult::success(format!("({}) {}-{}", &raw[..3], &raw[3..6], &raw[6..])), 10 => { @@ -135,7 +135,7 @@ impl CustomFormatter for CreditCardFormatter { let len = raw.chars().count(); match len { - 0..=15 => FormattingResult::warning(formatted, format!("Card incomplete ({}/16 digits)", len)), + 0..=15 => FormattingResult::warning(formatted, format!("Card incomplete ({len}/16 digits)")), 16 => FormattingResult::success(formatted), _ => FormattingResult::warning(formatted, "Card too long (extra digits shown)"), } @@ -177,16 +177,16 @@ impl CustomFormatter for DateFormatter { if m == 0 || m > 12 { FormattingResult::warning( - format!("{}/{}/{}", month, day, year), + format!("{month}/{day}/{year}"), "Invalid month (01-12)" ) } else if d == 0 || d > 31 { FormattingResult::warning( - format!("{}/{}/{}", month, day, year), + format!("{month}/{day}/{year}"), "Invalid day (01-31)" ) } else { - FormattingResult::success(format!("{}/{}/{}", month, day, year)) + FormattingResult::success(format!("{month}/{day}/{year}")) } }, _ => FormattingResult::error("Date too long (MMDDYYYY format)"), @@ -384,7 +384,7 @@ impl EnhancedDemoEditor { let warning = if self.validation_enabled && self.has_formatter() { // Check if there are any formatting warnings - if raw.len() > 0 { + if !raw.is_empty() { match self.editor.current_field() { 0 if raw.len() < 5 => Some(format!("PSC incomplete: {}/5", raw.len())), 1 if raw.len() < 10 => Some(format!("Phone incomplete: {}/10", raw.len())), @@ -408,7 +408,7 @@ impl EnhancedDemoEditor { self.editor.enter_edit_mode(); let field_type = self.current_field_type(); let rules = self.get_input_rules(); - self.debug_message = format!("โœ๏ธ INSERT MODE - Cursor: Steady Bar | - {} - {}", field_type, rules); + self.debug_message = format!("โœ๏ธ INSERT MODE - Cursor: Steady Bar | - {field_type} - {rules}"); } fn exit_edit_mode(&mut self) { @@ -429,9 +429,9 @@ impl EnhancedDemoEditor { if result.is_ok() { let (raw, display, _, _) = self.get_current_field_analysis(); if raw != display && self.validation_enabled { - self.debug_message = format!("โœ๏ธ '{}' added - Real-time formatting active", ch); + self.debug_message = format!("โœ๏ธ '{ch}' added - Real-time formatting active"); } else { - self.debug_message = format!("โœ๏ธ '{}' added", ch); + self.debug_message = format!("โœ๏ธ '{ch}' added"); } } result @@ -459,7 +459,7 @@ impl EnhancedDemoEditor { display.chars().nth(display_pos).unwrap_or('โˆ…') ); } else { - self.debug_message = format!("๐Ÿ“ Cursor at position {} (no mapping needed)", raw_pos); + self.debug_message = format!("๐Ÿ“ Cursor at position {raw_pos} (no mapping needed)"); } } @@ -530,7 +530,7 @@ fn handle_key_press( // Field analysis (AppMode::ReadOnly, KeyCode::Char('?'), _) => { let (raw, display, status, warning) = editor.get_current_field_analysis(); - let warning_text = warning.map(|w| format!(" โš ๏ธ {}", w)).unwrap_or_default(); + let warning_text = warning.map(|w| format!(" โš ๏ธ {w}")).unwrap_or_default(); editor.debug_message = format!( "๐Ÿ” Field {}: {} | Raw: '{}' | Display: '{}'{}", editor.current_field() + 1, status, raw, display, warning_text @@ -558,7 +558,7 @@ fn run_app( } } Err(e) => { - editor.debug_message = format!("โŒ Error: {}", e); + editor.debug_message = format!("โŒ Error: {e}"); } } } @@ -627,11 +627,11 @@ fn render_enhanced_status( ]; if editor.show_raw_data || editor.mode() == AppMode::Edit { - analysis_lines.push(format!("๐Ÿ’พ Raw Data: '{}'", raw)); - analysis_lines.push(format!("โœจ Display: '{}'", display)); + analysis_lines.push(format!("๐Ÿ’พ Raw Data: '{raw}'")); + analysis_lines.push(format!("โœจ Display: '{display}'")); } else { - analysis_lines.push(format!("โœจ User Sees: '{}'", display)); - analysis_lines.push(format!("๐Ÿ’พ Stored As: '{}'", raw)); + analysis_lines.push(format!("โœจ User Sees: '{display}'")); + analysis_lines.push(format!("๐Ÿ’พ Stored As: '{raw}'")); } if editor.show_cursor_details { @@ -643,7 +643,7 @@ fn render_enhanced_status( } if let Some(ref warn) = warning { - analysis_lines.push(format!("โš ๏ธ Warning: {}", warn)); + analysis_lines.push(format!("โš ๏ธ Warning: {warn}")); } let analysis_color = if warning.is_some() { @@ -742,7 +742,7 @@ fn main() -> Result<(), Box> { CursorManager::reset()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐Ÿงฉ Enhanced custom formatter demo completed!"); diff --git a/canvas/examples/validation_5.rs b/canvas/examples/validation_5.rs index 56d3484..5aca418 100644 --- a/canvas/examples/validation_5.rs +++ b/canvas/examples/validation_5.rs @@ -203,7 +203,7 @@ impl ValidationServices { /// PSC validation: simulates postal service API lookup fn validate_psc(&mut self, psc: &str) -> ExternalValidationState { - let cache_key = format!("psc:{}", psc); + let cache_key = format!("psc:{psc}"); if let Some(cached) = self.cache.get(&cache_key) { return cached.clone(); } @@ -244,7 +244,7 @@ impl ValidationServices { "20" | "21" => "Brno region", _ => "Valid postal region" }; - ExternalValidationState::Valid(Some(format!("{} - verified", region))) + ExternalValidationState::Valid(Some(format!("{region} - verified"))) } }; @@ -254,7 +254,7 @@ impl ValidationServices { /// Email validation: simulates domain checking fn validate_email(&mut self, email: &str) -> ExternalValidationState { - let cache_key = format!("email:{}", email); + let cache_key = format!("email:{email}"); if let Some(cached) = self.cache.get(&cache_key) { return cached.clone(); } @@ -315,7 +315,7 @@ impl ValidationServices { /// Username validation: simulates availability checking fn validate_username(&mut self, username: &str) -> ExternalValidationState { - let cache_key = format!("username:{}", username); + let cache_key = format!("username:{username}"); if let Some(cached) = self.cache.get(&cache_key) { return cached.clone(); } @@ -371,7 +371,7 @@ impl ValidationServices { /// API Key validation: simulates authentication service fn validate_api_key(&mut self, key: &str) -> ExternalValidationState { - let cache_key = format!("apikey:{}", key); + let cache_key = format!("apikey:{key}"); if let Some(cached) = self.cache.get(&cache_key) { return cached.clone(); } @@ -429,7 +429,7 @@ impl ValidationServices { /// Credit Card validation: simulates bank verification fn validate_credit_card(&mut self, card: &str) -> ExternalValidationState { - let cache_key = format!("card:{}", card); + let cache_key = format!("card:{card}"); if let Some(cached) = self.cache.get(&cache_key) { return cached.clone(); } @@ -724,8 +724,7 @@ impl ValidationDemoEditor { let duration_ms = result.duration().as_millis(); let cached_text = if result.cached { " (cached)" } else { "" }; self.debug_message = format!( - "๐Ÿ” {} validation completed in {}ms{} (manual)", - validation_type, duration_ms, cached_text + "๐Ÿ” {validation_type} validation completed in {duration_ms}ms{cached_text} (manual)" ); } @@ -812,7 +811,7 @@ impl ValidationDemoEditor { 0 }; - format!("Total: {} validations, Avg: {}ms", total_validations, avg_time_ms) + format!("Total: {total_validations} validations, Avg: {avg_time_ms}ms") } fn get_field_validation_state(&self, field_index: usize) -> ExternalValidationState { @@ -1032,8 +1031,8 @@ fn render_validation_panel( }; let field_line = Line::from(vec![ - Span::styled(format!("{}{}: ", indicator, field_name), Style::default().fg(Color::White)), - Span::raw(format!("'{}' โ†’ ", value_display)), + Span::styled(format!("{indicator}{field_name}: "), Style::default().fg(Color::White)), + Span::raw(format!("'{value_display}' โ†’ ")), Span::styled(state_text.to_string(), Style::default().fg(color)), ]); @@ -1077,8 +1076,7 @@ fn render_validation_panel( }; ListItem::new(format!( - "{}: '{}' โ†’ {} ({}ms{})", - field_name, short_value, state_summary, duration_ms, cached_text + "{field_name}: '{short_value}' โ†’ {state_summary} ({duration_ms}ms{cached_text})" )) }) .collect(); @@ -1162,7 +1160,7 @@ fn main() -> Result<(), Box> { CursorManager::reset()?; if let Err(err) = res { - println!("{:?}", err); + println!("{err:?}"); } println!("๐Ÿงช Enhanced fully automatic external validation demo completed!"); diff --git a/canvas/src/canvas/cursor.rs b/canvas/src/canvas/cursor.rs index 2db839c..c11dd4f 100644 --- a/canvas/src/canvas/cursor.rs +++ b/canvas/src/canvas/cursor.rs @@ -19,7 +19,7 @@ impl CursorManager { #[cfg(feature = "textmode-normal")] { let style = SetCursorStyle::SteadyBar; - return execute!(io::stdout(), style); + execute!(io::stdout(), style) } // Default (not normal): original mapping diff --git a/canvas/src/canvas/gui.rs b/canvas/src/canvas/gui.rs index fd857f0..111f12a 100644 --- a/canvas/src/canvas/gui.rs +++ b/canvas/src/canvas/gui.rs @@ -486,7 +486,7 @@ fn render_field_labels( ) { for (i, field) in fields.iter().enumerate() { let label = Paragraph::new(Line::from(Span::styled( - format!("{}:", field), + format!("{field}:"), Style::default().fg(theme.fg()), ))); f.render_widget( @@ -595,50 +595,48 @@ fn apply_characterwise_highlighting<'a, T: CanvasTheme>( Span::styled(highlighted, highlight_style), Span::styled(after, normal_style), ]) - } else { - if field_index == anchor_field { - if anchor_field < *current_field_idx { - let clamped_start = anchor_char.min(text_len); - let before: String = text.chars().take(clamped_start).collect(); - let highlighted: String = text.chars().skip(clamped_start).collect(); + } else if field_index == anchor_field { + if anchor_field < *current_field_idx { + let clamped_start = anchor_char.min(text_len); + let before: String = text.chars().take(clamped_start).collect(); + let highlighted: String = text.chars().skip(clamped_start).collect(); - Line::from(vec![ - Span::styled(before, normal_style), - Span::styled(highlighted, highlight_style), - ]) - } else { - let clamped_end = anchor_char.min(text_len); - let highlighted: String = text.chars().take(clamped_end + 1).collect(); - let after: String = text.chars().skip(clamped_end + 1).collect(); - - Line::from(vec![ - Span::styled(highlighted, highlight_style), - Span::styled(after, normal_style), - ]) - } - } else if field_index == *current_field_idx { - if anchor_field < *current_field_idx { - let clamped_end = current_cursor_pos.min(text_len); - let highlighted: String = text.chars().take(clamped_end + 1).collect(); - let after: String = text.chars().skip(clamped_end + 1).collect(); - - Line::from(vec![ - Span::styled(highlighted, highlight_style), - Span::styled(after, normal_style), - ]) - } else { - let clamped_start = current_cursor_pos.min(text_len); - let before: String = text.chars().take(clamped_start).collect(); - let highlighted: String = text.chars().skip(clamped_start).collect(); - - Line::from(vec![ - Span::styled(before, normal_style), - Span::styled(highlighted, highlight_style), - ]) - } + Line::from(vec![ + Span::styled(before, normal_style), + Span::styled(highlighted, highlight_style), + ]) } else { - Line::from(Span::styled(text, highlight_style)) + let clamped_end = anchor_char.min(text_len); + let highlighted: String = text.chars().take(clamped_end + 1).collect(); + let after: String = text.chars().skip(clamped_end + 1).collect(); + + Line::from(vec![ + Span::styled(highlighted, highlight_style), + Span::styled(after, normal_style), + ]) } + } else if field_index == *current_field_idx { + if anchor_field < *current_field_idx { + let clamped_end = current_cursor_pos.min(text_len); + let highlighted: String = text.chars().take(clamped_end + 1).collect(); + let after: String = text.chars().skip(clamped_end + 1).collect(); + + Line::from(vec![ + Span::styled(highlighted, highlight_style), + Span::styled(after, normal_style), + ]) + } else { + let clamped_start = current_cursor_pos.min(text_len); + let before: String = text.chars().take(clamped_start).collect(); + let highlighted: String = text.chars().skip(clamped_start).collect(); + + Line::from(vec![ + Span::styled(before, normal_style), + Span::styled(highlighted, highlight_style), + ]) + } + } else { + Line::from(Span::styled(text, highlight_style)) } } else { Line::from(Span::styled(text, normal_style)) @@ -710,6 +708,6 @@ pub fn render_canvas_default( area: Rect, editor: &FormEditor, ) -> Option { - let theme = DefaultCanvasTheme::default(); + let theme = DefaultCanvasTheme; render_canvas(f, area, editor, &theme) } diff --git a/canvas/src/canvas/modes/highlight.rs b/canvas/src/canvas/modes/highlight.rs index 55c5a18..7bf63c0 100644 --- a/canvas/src/canvas/modes/highlight.rs +++ b/canvas/src/canvas/modes/highlight.rs @@ -2,14 +2,11 @@ // canvas/src/modes/highlight.rs #[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Default)] pub enum HighlightState { + #[default] Off, Characterwise { anchor: (usize, usize) }, // (field_index, char_position) Linewise { anchor_line: usize }, // field_index } -impl Default for HighlightState { - fn default() -> Self { - HighlightState::Off - } -} diff --git a/canvas/src/canvas/modes/manager.rs b/canvas/src/canvas/modes/manager.rs index 854374c..3ad9d4b 100644 --- a/canvas/src/canvas/modes/manager.rs +++ b/canvas/src/canvas/modes/manager.rs @@ -39,7 +39,7 @@ impl ModeManager { #[cfg(feature = "textmode-normal")] { // Always force Edit in normalmode - return Ok(AppMode::Edit); + Ok(AppMode::Edit) } #[cfg(not(feature = "textmode-normal"))] diff --git a/canvas/src/editor/mode.rs b/canvas/src/editor/mode.rs index a7bae11..e638082 100644 --- a/canvas/src/editor/mode.rs +++ b/canvas/src/editor/mode.rs @@ -25,7 +25,6 @@ impl FormEditor { { let _ = CursorManager::update_for_mode(AppMode::Edit); } - return; } // Default (not normal): original vim behavior @@ -119,7 +118,7 @@ impl FormEditor { { self.close_suggestions(); } - return Ok(()); + Ok(()) } // Default (not normal): original vim behavior @@ -155,7 +154,6 @@ impl FormEditor { { let _ = CursorManager::update_for_mode(AppMode::Edit); } - return; } // Default (not normal): vim behavior @@ -169,7 +167,6 @@ impl FormEditor { // NORMALMODE: ignore request (stay in Edit) #[cfg(feature = "textmode-normal")] { - return; } // Default (not normal): original vim @@ -193,7 +190,6 @@ impl FormEditor { // NORMALMODE: ignore #[cfg(feature = "textmode-normal")] { - return; } // Default (not normal): original vim @@ -216,7 +212,6 @@ impl FormEditor { // NORMALMODE: ignore #[cfg(feature = "textmode-normal")] { - return; } // Default (not normal): original vim @@ -237,7 +232,7 @@ impl FormEditor { pub fn is_highlight_mode(&self) -> bool { #[cfg(feature = "textmode-normal")] { - return false; + false } #[cfg(not(feature = "textmode-normal"))] { diff --git a/canvas/src/editor/movement.rs b/canvas/src/editor/movement.rs index 5f76626..521f5ce 100644 --- a/canvas/src/editor/movement.rs +++ b/canvas/src/editor/movement.rs @@ -46,12 +46,11 @@ impl FormEditor { } } - if !moved { - if self.ui_state.cursor_pos > 0 { + if !moved + && self.ui_state.cursor_pos > 0 { self.ui_state.cursor_pos -= 1; self.ui_state.ideal_cursor_column = self.ui_state.cursor_pos; } - } Ok(()) } @@ -141,7 +140,7 @@ impl FormEditor { // Successfully moved to next field, try to find first 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_word_pos = if new_text.chars().next().is_some_and(|c| !c.is_whitespace()) { // Field starts with non-whitespace, go to position 0 0 } else { @@ -177,7 +176,7 @@ impl FormEditor { 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()) { + let first_word_pos = if new_text.chars().next().is_some_and(|c| !c.is_whitespace()) { // Field starts with non-whitespace, go to position 0 0 } else { @@ -419,7 +418,7 @@ impl FormEditor { // Successfully moved to next field, try to find first big_word let new_text = self.current_text(); if !new_text.is_empty() { - let first_big_word_pos = if new_text.chars().next().map_or(false, |c| !c.is_whitespace()) { + let first_big_word_pos = if new_text.chars().next().is_some_and(|c| !c.is_whitespace()) { // Field starts with non-whitespace, go to position 0 0 } else { @@ -455,7 +454,7 @@ impl FormEditor { self.ui_state.ideal_cursor_column = 0; } else { // Find first big_word in new field - let first_big_word_pos = if new_text.chars().next().map_or(false, |c| !c.is_whitespace()) { + let first_big_word_pos = if new_text.chars().next().is_some_and(|c| !c.is_whitespace()) { // Field starts with non-whitespace, go to position 0 0 } else { @@ -644,8 +643,8 @@ impl FormEditor { if current_text.is_empty() { let current_field = self.ui_state.current_field; - if self.move_up().is_ok() { - if self.ui_state.current_field != current_field { + if self.move_up().is_ok() + && self.ui_state.current_field != current_field { let new_text = self.current_text(); if !new_text.is_empty() { // Find first big_word end in new field @@ -654,7 +653,6 @@ impl FormEditor { self.ui_state.ideal_cursor_column = last_big_word_end; } } - } return; } @@ -664,8 +662,8 @@ impl FormEditor { // Only try to cross fields if we didn't move at all (stayed at same position) if new_pos == current_pos { let current_field = self.ui_state.current_field; - if self.move_up().is_ok() { - if self.ui_state.current_field != current_field { + if self.move_up().is_ok() + && self.ui_state.current_field != current_field { let new_text = self.current_text(); if !new_text.is_empty() { let last_big_word_end = find_big_word_end(new_text, 0); @@ -673,7 +671,6 @@ impl FormEditor { self.ui_state.ideal_cursor_column = last_big_word_end; } } - } } else { // Normal big_word movement within current field let is_edit_mode = self.ui_state.current_mode == AppMode::Edit; diff --git a/canvas/src/suggestions/gui.rs b/canvas/src/suggestions/gui.rs index 986af1f..422be26 100644 --- a/canvas/src/suggestions/gui.rs +++ b/canvas/src/suggestions/gui.rs @@ -149,8 +149,8 @@ fn calculate_dropdown_position( if dropdown_area.right() > frame_area.width { dropdown_area.x = frame_area.width.saturating_sub(dropdown_width); } - dropdown_area.x = dropdown_area.x.max(0); - dropdown_area.y = dropdown_area.y.max(0); + dropdown_area.x = dropdown_area.x; + dropdown_area.y = dropdown_area.y; dropdown_area } diff --git a/canvas/src/textarea/state.rs b/canvas/src/textarea/state.rs index 39c091a..82b0f75 100644 --- a/canvas/src/textarea/state.rs +++ b/canvas/src/textarea/state.rs @@ -355,7 +355,7 @@ impl TextAreaState { #[cfg(feature = "gui")] pub fn cursor(&self, area: Rect, block: Option<&Block<'_>>) -> (u16, u16) { let inner = if let Some(b) = block { b.inner(area) } else { area }; - let line_idx = self.current_field() as usize; + let line_idx = self.current_field(); match self.overflow_mode { TextOverflowMode::Wrap => { @@ -375,7 +375,7 @@ impl TextAreaState { let col_chars = self.display_cursor_position(); let (subrow, x_cols) = wrapped_rows_to_cursor_indented( - ¤t_line, + current_line, width, indent, col_chars, @@ -478,7 +478,7 @@ impl TextAreaState { } let indent = self.wrap_indent_cols; - let line_idx = self.current_field() as usize; + let line_idx = self.current_field(); let prefix_rows = self.visual_rows_before_line_and_intra_indented(width, line_idx); @@ -487,7 +487,7 @@ impl TextAreaState { let col = self.display_cursor_position(); let (subrow, _x_cols) = - wrapped_rows_to_cursor_indented(¤t_line, width, indent, col); + wrapped_rows_to_cursor_indented(current_line, width, indent, col); let caret_vis_row = prefix_rows.saturating_add(subrow); diff --git a/canvas/src/textarea/widget.rs b/canvas/src/textarea/widget.rs index 486b966..d0e8a75 100644 --- a/canvas/src/textarea/widget.rs +++ b/canvas/src/textarea/widget.rs @@ -314,11 +314,11 @@ impl<'a> StatefulWidget for TextArea<'a> { match state.overflow_mode { TextOverflowMode::Wrap => unreachable!(), TextOverflowMode::Indicator { ch } => { - let fits = display_width(&s) <= inner.width; + let fits = display_width(s) <= inner.width; let start_cols = if i == state.current_field() { let col_idx = state.display_cursor_position(); - let cursor_cols = display_cols_up_to(&s, col_idx); + let cursor_cols = display_cols_up_to(s, col_idx); let (target_h, _left_cols) = compute_h_scroll_with_padding(cursor_cols, inner.width); @@ -332,7 +332,7 @@ impl<'a> StatefulWidget for TextArea<'a> { }; display_lines.push(clip_window_with_indicator_padded( - &s, + s, inner.width, ch, start_cols, diff --git a/canvas/src/validation/formatting.rs b/canvas/src/validation/formatting.rs index eca5eb3..7ce6ca2 100644 --- a/canvas/src/validation/formatting.rs +++ b/canvas/src/validation/formatting.rs @@ -108,7 +108,7 @@ impl FormattingResult { pub fn success(formatted: impl Into) -> Self { FormattingResult::Success { formatted: formatted.into(), - mapper: Arc::new(DefaultPositionMapper::default()), + mapper: Arc::new(DefaultPositionMapper), } } @@ -117,7 +117,7 @@ impl FormattingResult { FormattingResult::Warning { formatted: formatted.into(), message: message.into(), - mapper: Arc::new(DefaultPositionMapper::default()), + mapper: Arc::new(DefaultPositionMapper), } } @@ -187,7 +187,7 @@ mod tests { #[test] fn default_mapper_roundtrip_basic() { - let mapper = DefaultPositionMapper::default(); + let mapper = DefaultPositionMapper; let raw = "01001"; let formatted = "010 01"; diff --git a/canvas/src/validation/limits.rs b/canvas/src/validation/limits.rs index e1f75b9..1a0354b 100644 --- a/canvas/src/validation/limits.rs +++ b/canvas/src/validation/limits.rs @@ -23,8 +23,10 @@ pub struct CharacterLimits { /// How to count characters for limit checking #[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Default)] pub enum CountMode { /// Count actual characters (default) + #[default] Characters, /// Count display width (useful for CJK characters) @@ -34,11 +36,6 @@ pub enum CountMode { Bytes, } -impl Default for CountMode { - fn default() -> Self { - CountMode::Characters - } -} /// Result of a character limit check #[derive(Debug, Clone, PartialEq, Eq)] @@ -157,9 +154,7 @@ impl CharacterLimits { if let Some(max) = self.max_length { if new_count > max { return Some(ValidationResult::error(format!( - "Character limit exceeded: {}/{}", - new_count, - max + "Character limit exceeded: {new_count}/{max}" ))); } @@ -167,9 +162,7 @@ impl CharacterLimits { if let Some(warning_threshold) = self.warning_threshold { if new_count >= warning_threshold && current_count < warning_threshold { return Some(ValidationResult::warning(format!( - "Approaching character limit: {}/{}", - new_count, - max + "Approaching character limit: {new_count}/{max}" ))); } } @@ -186,9 +179,7 @@ impl CharacterLimits { if let Some(min) = self.min_length { if count < min { return Some(ValidationResult::warning(format!( - "Minimum length not met: {}/{}", - count, - min + "Minimum length not met: {count}/{min}" ))); } } @@ -197,9 +188,7 @@ impl CharacterLimits { if let Some(max) = self.max_length { if count > max { return Some(ValidationResult::error(format!( - "Character limit exceeded: {}/{}", - count, - max + "Character limit exceeded: {count}/{max}" ))); } @@ -207,9 +196,7 @@ impl CharacterLimits { if let Some(warning_threshold) = self.warning_threshold { if count >= warning_threshold { return Some(ValidationResult::warning(format!( - "Approaching character limit: {}/{}", - count, - max + "Approaching character limit: {count}/{max}" ))); } } @@ -251,20 +238,16 @@ impl CharacterLimits { match self.check_limits(text) { LimitCheckResult::Ok => { // Show current/max if we have a max limit - if let Some(max) = self.max_length { - Some(format!("{}/{}", self.count(text), max)) - } else { - None - } + self.max_length.map(|max| format!("{}/{}", self.count(text), max)) }, LimitCheckResult::Warning { current, max } => { - Some(format!("{}/{} (approaching limit)", current, max)) + Some(format!("{current}/{max} (approaching limit)")) }, LimitCheckResult::Exceeded { current, max } => { - Some(format!("{}/{} (exceeded)", current, max)) + Some(format!("{current}/{max} (exceeded)")) }, LimitCheckResult::TooShort { current, min } => { - Some(format!("{}/{} minimum", current, min)) + Some(format!("{current}/{min} minimum")) }, } } @@ -284,8 +267,7 @@ impl CharacterLimits { let count = self.count(text); if count > 0 && count < min { return Some(format!( - "Field must be empty or have at least {} characters (currently: {})", - min, count + "Field must be empty or have at least {min} characters (currently: {count})" )); } } diff --git a/canvas/src/validation/mask.rs b/canvas/src/validation/mask.rs index 7539740..716903a 100644 --- a/canvas/src/validation/mask.rs +++ b/canvas/src/validation/mask.rs @@ -2,9 +2,11 @@ //! Pure display mask system - user-defined patterns only #[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Default)] pub enum MaskDisplayMode { /// Only show separators as user types /// Example: "" โ†’ "", "123" โ†’ "123", "12345" โ†’ "(123) 45" + #[default] Dynamic, /// Show full template with placeholders from start @@ -15,11 +17,6 @@ pub enum MaskDisplayMode { }, } -impl Default for MaskDisplayMode { - fn default() -> Self { - MaskDisplayMode::Dynamic - } -} #[derive(Debug, Clone, PartialEq, Eq)] pub struct DisplayMask { diff --git a/canvas/src/validation/patterns.rs b/canvas/src/validation/patterns.rs index 91f07d5..07ae225 100644 --- a/canvas/src/validation/patterns.rs +++ b/canvas/src/validation/patterns.rs @@ -49,8 +49,8 @@ impl std::fmt::Debug for CharacterFilter { CharacterFilter::Alphabetic => write!(f, "Alphabetic"), CharacterFilter::Numeric => write!(f, "Numeric"), CharacterFilter::Alphanumeric => write!(f, "Alphanumeric"), - CharacterFilter::Exact(ch) => write!(f, "Exact('{}')", ch), - CharacterFilter::OneOf(chars) => write!(f, "OneOf({:?})", chars), + CharacterFilter::Exact(ch) => write!(f, "Exact('{ch}')"), + CharacterFilter::OneOf(chars) => write!(f, "OneOf({chars:?})"), CharacterFilter::Custom(_) => write!(f, "Custom()"), } } @@ -130,10 +130,10 @@ impl CharacterFilter { CharacterFilter::Alphabetic => "alphabetic characters (a-z, A-Z)".to_string(), CharacterFilter::Numeric => "numeric characters (0-9)".to_string(), CharacterFilter::Alphanumeric => "alphanumeric characters (a-z, A-Z, 0-9)".to_string(), - CharacterFilter::Exact(ch) => format!("exactly '{}'", ch), + CharacterFilter::Exact(ch) => format!("exactly '{ch}'"), CharacterFilter::OneOf(chars) => { let char_list: String = chars.iter().collect(); - format!("one of: {}", char_list) + format!("one of: {char_list}") }, CharacterFilter::Custom(_) => "custom filter".to_string(), } @@ -207,9 +207,7 @@ impl PatternFilters { /// Validate entire text against all filters pub fn validate_text(&self, text: &str) -> Result<(), String> { for (position, character) in text.char_indices() { - if let Err(error) = self.validate_char_at_position(position, character) { - return Err(error); - } + self.validate_char_at_position(position, character)? } Ok(()) }