compiled examples

This commit is contained in:
Priec
2025-08-11 22:50:28 +02:00
parent 280f314100
commit 082093ea17
4 changed files with 79 additions and 83 deletions

View File

@@ -34,7 +34,6 @@ use ratatui::{
widgets::{Block, Borders, Paragraph, Wrap}, widgets::{Block, Borders, Paragraph, Wrap},
Frame, Terminal, Frame, Terminal,
}; };
use canvas::{ use canvas::{
canvas::{ canvas::{
gui::render_canvas_default, gui::render_canvas_default,
@@ -62,10 +61,8 @@ struct ValidationFormEditor<D: DataProvider> {
impl<D: DataProvider> ValidationFormEditor<D> { impl<D: DataProvider> ValidationFormEditor<D> {
fn new(data_provider: D) -> Self { fn new(data_provider: D) -> Self {
let mut editor = FormEditor::new(data_provider); let mut editor = FormEditor::new(data_provider);
// Enable validation by default // Enable validation by default
editor.set_validation_enabled(true); editor.set_validation_enabled(true);
Self { Self {
editor, editor,
has_unsaved_changes: false, has_unsaved_changes: false,
@@ -98,7 +95,6 @@ impl<D: DataProvider> ValidationFormEditor<D> {
fn toggle_validation(&mut self) { fn toggle_validation(&mut self) {
self.validation_enabled = !self.validation_enabled; self.validation_enabled = !self.validation_enabled;
self.editor.set_validation_enabled(self.validation_enabled); self.editor.set_validation_enabled(self.validation_enabled);
if self.validation_enabled { if self.validation_enabled {
self.debug_message = "✅ Validation ENABLED - Try exceeding limits!".to_string(); self.debug_message = "✅ Validation ENABLED - Try exceeding limits!".to_string();
} else { } else {
@@ -110,14 +106,12 @@ impl<D: DataProvider> ValidationFormEditor<D> {
if !self.validation_enabled { if !self.validation_enabled {
return (true, None); return (true, None);
} }
let can_switch = self.editor.can_switch_fields(); let can_switch = self.editor.can_switch_fields();
let reason = if !can_switch { let reason = if !can_switch {
self.editor.field_switch_block_reason() self.editor.field_switch_block_reason()
} else { } else {
None None
}; };
(can_switch, reason) (can_switch, reason)
} }
@@ -125,11 +119,9 @@ impl<D: DataProvider> ValidationFormEditor<D> {
if !self.validation_enabled { if !self.validation_enabled {
return "❌ DISABLED".to_string(); return "❌ DISABLED".to_string();
} }
if self.field_switch_blocked { if self.field_switch_blocked {
return "🚫 SWITCH BLOCKED".to_string(); return "🚫 SWITCH BLOCKED".to_string();
} }
let summary = self.editor.validation_summary(); let summary = self.editor.validation_summary();
if summary.has_errors() { if summary.has_errors() {
format!("{} ERRORS", summary.error_fields) format!("{} ERRORS", summary.error_fields)
@@ -162,7 +154,6 @@ impl<D: DataProvider> ValidationFormEditor<D> {
for i in 0..field_count { for i in 0..field_count {
self.editor.validate_field(i); self.editor.validate_field(i);
} }
let summary = self.editor.validation_summary(); let summary = self.editor.validation_summary();
self.debug_message = format!( self.debug_message = format!(
"🔍 Validated all fields: {} valid, {} warnings, {} errors", "🔍 Validated all fields: {} valid, {} warnings, {} errors",
@@ -250,7 +241,6 @@ impl<D: DataProvider> ValidationFormEditor<D> {
if !self.validation_enabled { if !self.validation_enabled {
return; return;
} }
if let Some(result) = self.editor.current_field_validation() { if let Some(result) = self.editor.current_field_validation() {
match result { match result {
ValidationResult::Valid => { ValidationResult::Valid => {
@@ -298,7 +288,10 @@ impl<D: DataProvider> ValidationFormEditor<D> {
ValidationResult::Valid => { ValidationResult::Valid => {
// Don't spam with valid messages, just show character count if applicable // Don't spam with valid messages, just show character count if applicable
if let Some(limits) = self.get_current_field_limits() { if let Some(limits) = self.get_current_field_limits() {
if let Some(status) = limits.status_text(self.editor.current_text()) { 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); self.debug_message = format!("✏️ {}", status);
} }
} }
@@ -537,7 +530,6 @@ fn handle_key_press(
editor.enter_edit_mode(); editor.enter_edit_mode();
editor.clear_command_buffer(); editor.clear_command_buffer();
} }
// Escape: Exit edit mode // Escape: Exit edit mode
(_, KeyCode::Esc, _) => { (_, KeyCode::Esc, _) => {
if mode == AppMode::Edit { if mode == AppMode::Edit {
@@ -630,7 +622,6 @@ fn handle_key_press(
summary.validated_fields summary.validated_fields
)); ));
} }
_ => { _ => {
if editor.has_pending_command() { if editor.has_pending_command() {
editor.clear_command_buffer(); editor.clear_command_buffer();
@@ -662,7 +653,6 @@ fn run_app<B: Backend>(
} }
} }
} }
Ok(()) Ok(())
} }
@@ -706,27 +696,27 @@ fn render_validation_status(
}; };
let validation_status = editor.get_validation_status(); let validation_status = editor.get_validation_status();
let status_text = if editor.has_pending_command() { let status_text = if editor.has_pending_command() {
format!("-- {} -- {} [{}] | Validation: {}", format!("-- {} -- {} [{}] | Validation: {}",
mode_text, editor.debug_message(), editor.get_command_buffer(), validation_status) mode_text, editor.debug_message(), editor.get_command_buffer(), validation_status)
} else if editor.has_unsaved_changes() { } else if editor.has_unsaved_changes() {
format!("-- {} -- [Modified] {} | Validation: {}", format!("-- {} -- [Modified] {} | Validation: {}",
mode_text, editor.debug_message(), validation_status) mode_text, editor.debug_message(), validation_status)
} else { } else {
format!("-- {} -- {} | Validation: {}", format!("-- {} -- {} | Validation: {}",
mode_text, editor.debug_message(), validation_status) mode_text, editor.debug_message(), validation_status)
}; };
let status = Paragraph::new(Line::from(Span::raw(status_text))) let status = Paragraph::new(Line::from(Span::raw(status_text)))
.block(Block::default().borders(Borders::ALL).title("🔍 Validation Status")); .block(Block::default().borders(Borders::ALL).title("🔍 Validation Status"));
f.render_widget(status, chunks[0]); f.render_widget(status, chunks[0]);
// Validation summary with field switching info // Validation summary with field switching info
let summary = editor.editor.validation_summary(); let summary = editor.editor.validation_summary();
let summary_text = if editor.validation_enabled { let summary_text = if editor.validation_enabled {
let switch_info = if editor.field_switch_blocked { let switch_info = if editor.field_switch_blocked {
format!("\n🚫 Field switching blocked: {}", format!("\n🚫 Field switching blocked: {}",
editor.block_reason.as_deref().unwrap_or("Unknown reason")) editor.block_reason.as_deref().unwrap_or("Unknown reason"))
} else { } else {
let (can_switch, reason) = editor.check_field_switch_allowed(); let (can_switch, reason) = editor.check_field_switch_allowed();
@@ -765,7 +755,6 @@ fn render_validation_status(
.block(Block::default().borders(Borders::ALL).title("📈 Validation Overview")) .block(Block::default().borders(Borders::ALL).title("📈 Validation Overview"))
.style(summary_style) .style(summary_style)
.wrap(Wrap { trim: true }); .wrap(Wrap { trim: true });
f.render_widget(validation_summary, chunks[1]); f.render_widget(validation_summary, chunks[1]);
// Enhanced help text // Enhanced help text
@@ -792,7 +781,6 @@ fn render_validation_status(
.block(Block::default().borders(Borders::ALL).title("🚀 Validation Commands")) .block(Block::default().borders(Borders::ALL).title("🚀 Validation Commands"))
.style(Style::default().fg(Color::Gray)) .style(Style::default().fg(Color::Gray))
.wrap(Wrap { trim: true }); .wrap(Wrap { trim: true });
f.render_widget(help, chunks[2]); f.render_widget(help, chunks[2]);
} }
@@ -817,10 +805,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = ValidationDemoData::new(); let data = ValidationDemoData::new();
let mut editor = ValidationFormEditor::new(data); let mut editor = ValidationFormEditor::new(data);
// Initialize with normal mode - library automatically sets block cursor // Initialize with normal mode - library automatically sets block cursor
editor.set_mode(AppMode::ReadOnly); editor.set_mode(AppMode::ReadOnly);
// Demonstrate that CursorManager is available and working // Demonstrate that CursorManager is available and working
CursorManager::update_for_mode(AppMode::ReadOnly)?; CursorManager::update_for_mode(AppMode::ReadOnly)?;

View File

@@ -71,12 +71,12 @@ impl<D: DataProvider> AdvancedPatternFormEditor<D> {
// ... (keeping all the same methods as before for brevity) // ... (keeping all the same methods as before for brevity)
// [All the previous methods: clear_command_buffer, add_to_command_buffer, etc.] // [All the previous methods: clear_command_buffer, add_to_command_buffer, etc.]
fn clear_command_buffer(&mut self) { self.command_buffer.clear(); } 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 add_to_command_buffer(&mut self, ch: char) { self.command_buffer.push(ch); }
fn get_command_buffer(&self) -> &str { &self.command_buffer } fn get_command_buffer(&self) -> &str { &self.command_buffer }
fn has_pending_command(&self) -> bool { !self.command_buffer.is_empty() } fn has_pending_command(&self) -> bool { !self.command_buffer.is_empty() }
fn toggle_validation(&mut self) { fn toggle_validation(&mut self) {
self.validation_enabled = !self.validation_enabled; self.validation_enabled = !self.validation_enabled;
self.editor.set_validation_enabled(self.validation_enabled); self.editor.set_validation_enabled(self.validation_enabled);
@@ -89,14 +89,14 @@ impl<D: DataProvider> AdvancedPatternFormEditor<D> {
fn move_left(&mut self) { self.editor.move_left(); self.field_switch_blocked = false; self.block_reason = None; } fn move_left(&mut self) { self.editor.move_left(); self.field_switch_blocked = false; self.block_reason = None; }
fn move_right(&mut self) { self.editor.move_right(); self.field_switch_blocked = false; self.block_reason = None; } fn move_right(&mut self) { self.editor.move_right(); self.field_switch_blocked = false; self.block_reason = None; }
fn move_up(&mut self) { fn move_up(&mut self) {
match self.editor.move_up() { match self.editor.move_up() {
Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; } 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) { fn move_down(&mut self) {
match self.editor.move_down() { match self.editor.move_down() {
Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; } Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; }
@@ -106,19 +106,19 @@ impl<D: DataProvider> AdvancedPatternFormEditor<D> {
fn move_line_start(&mut self) { self.editor.move_line_start(); } fn move_line_start(&mut self) { self.editor.move_line_start(); }
fn move_line_end(&mut self) { self.editor.move_line_end(); } fn move_line_end(&mut self) { self.editor.move_line_end(); }
fn enter_edit_mode(&mut self) { fn enter_edit_mode(&mut self) {
// Library will automatically update cursor to bar | in insert mode // Library will automatically update cursor to bar | in insert mode
self.editor.enter_edit_mode(); self.editor.enter_edit_mode();
self.debug_message = "✏️ INSERT MODE - Cursor: Steady Bar | - Testing advanced pattern validation".to_string(); self.debug_message = "✏️ INSERT MODE - Cursor: Steady Bar | - Testing advanced pattern validation".to_string();
} }
fn enter_append_mode(&mut self) { fn enter_append_mode(&mut self) {
// Library will automatically update cursor to bar | in insert mode // Library will automatically update cursor to bar | in insert mode
self.editor.enter_append_mode(); self.editor.enter_append_mode();
self.debug_message = "✏️ INSERT (append) - Cursor: Steady Bar | - Advanced patterns active".to_string(); self.debug_message = "✏️ INSERT (append) - Cursor: Steady Bar | - Advanced patterns active".to_string();
} }
fn exit_edit_mode(&mut self) { fn exit_edit_mode(&mut self) {
// Library will automatically update cursor to block █ in normal mode // Library will automatically update cursor to block █ in normal mode
self.editor.exit_edit_mode(); self.editor.exit_edit_mode();
@@ -156,7 +156,10 @@ impl<D: DataProvider> AdvancedPatternFormEditor<D> {
fn current_field(&self) -> usize { self.editor.current_field() } fn current_field(&self) -> usize { self.editor.current_field() }
fn cursor_position(&self) -> usize { self.editor.cursor_position() } fn cursor_position(&self) -> usize { self.editor.cursor_position() }
fn mode(&self) -> AppMode { self.editor.mode() } fn mode(&self) -> AppMode { self.editor.mode() }
fn current_text(&self) -> &str { self.editor.current_text() } fn current_text(&self) -> &str {
let field_index = self.editor.current_field();
self.editor.data_provider().field_value(field_index)
}
fn data_provider(&self) -> &D { self.editor.data_provider() } fn data_provider(&self) -> &D { self.editor.data_provider() }
fn ui_state(&self) -> &canvas::EditorState { self.editor.ui_state() } fn ui_state(&self) -> &canvas::EditorState { self.editor.ui_state() }
fn set_mode(&mut self, mode: AppMode) { self.editor.set_mode(mode); } fn set_mode(&mut self, mode: AppMode) { self.editor.set_mode(mode); }
@@ -384,7 +387,7 @@ impl DataProvider for AdvancedPatternData {
// Even positions (0,2,4...): vowels (a,e,i,o,u) // Even positions (0,2,4...): vowels (a,e,i,o,u)
// Odd positions (1,3,5...): consonants // Odd positions (1,3,5...): consonants
let vowels = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']; let vowels = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'];
// For demo purposes, we'll just accept alphabetic characters // For demo purposes, we'll just accept alphabetic characters
// In real usage, you'd implement the alternating logic based on position // In real usage, you'd implement the alternating logic based on position
c.is_alphabetic() c.is_alphabetic()

View File

@@ -108,7 +108,7 @@ impl<D: DataProvider> MaskDemoFormEditor<D> {
fn get_current_field_info(&self) -> (String, String, String) { fn get_current_field_info(&self) -> (String, String, String) {
let field_index = self.editor.current_field(); let field_index = self.editor.current_field();
let raw_data = self.editor.current_text(); let raw_data = self.editor.data_provider().field_value(field_index);
let display_data = if self.validation_enabled { let display_data = if self.validation_enabled {
self.editor.current_display_text() self.editor.current_display_text()
} else { } else {
@@ -117,8 +117,8 @@ impl<D: DataProvider> MaskDemoFormEditor<D> {
let mask_info = if let Some(config) = self.editor.validation_state().get_field_config(field_index) { let mask_info = if let Some(config) = self.editor.validation_state().get_field_config(field_index) {
if let Some(mask) = &config.display_mask { if let Some(mask) = &config.display_mask {
format!("Pattern: '{}', Mode: {:?}", format!("Pattern: '{}', Mode: {:?}",
mask.pattern(), mask.pattern(),
mask.display_mode()) mask.display_mode())
} else { } else {
"No mask configured".to_string() "No mask configured".to_string()
@@ -131,13 +131,13 @@ impl<D: DataProvider> MaskDemoFormEditor<D> {
} }
// === ENHANCED MOVEMENT WITH MASK AWARENESS === // === ENHANCED MOVEMENT WITH MASK AWARENESS ===
fn move_left(&mut self) { fn move_left(&mut self) {
self.editor.move_left(); self.editor.move_left();
self.update_cursor_info(); self.update_cursor_info();
} }
fn move_right(&mut self) { fn move_right(&mut self) {
self.editor.move_right(); self.editor.move_right();
self.update_cursor_info(); self.update_cursor_info();
} }
@@ -155,13 +155,13 @@ impl<D: DataProvider> MaskDemoFormEditor<D> {
} }
} }
fn move_line_start(&mut self) { fn move_line_start(&mut self) {
self.editor.move_line_start(); self.editor.move_line_start();
self.update_cursor_info(); self.update_cursor_info();
} }
fn move_line_end(&mut self) { fn move_line_end(&mut self) {
self.editor.move_line_end(); self.editor.move_line_end();
self.update_cursor_info(); self.update_cursor_info();
} }
@@ -237,12 +237,15 @@ impl<D: DataProvider> MaskDemoFormEditor<D> {
fn current_field(&self) -> usize { self.editor.current_field() } fn current_field(&self) -> usize { self.editor.current_field() }
fn cursor_position(&self) -> usize { self.editor.cursor_position() } fn cursor_position(&self) -> usize { self.editor.cursor_position() }
fn mode(&self) -> AppMode { self.editor.mode() } fn mode(&self) -> AppMode { self.editor.mode() }
fn current_text(&self) -> &str { self.editor.current_text() } fn current_text(&self) -> &str {
let field_index = self.editor.current_field();
self.editor.data_provider().field_value(field_index)
}
fn data_provider(&self) -> &D { self.editor.data_provider() } fn data_provider(&self) -> &D { self.editor.data_provider() }
fn ui_state(&self) -> &canvas::EditorState { self.editor.ui_state() } fn ui_state(&self) -> &canvas::EditorState { self.editor.ui_state() }
fn set_mode(&mut self, mode: AppMode) { fn set_mode(&mut self, mode: AppMode) {
// Library automatically updates cursor for the mode // Library automatically updates cursor for the mode
self.editor.set_mode(mode); self.editor.set_mode(mode);
} }
fn next_field(&mut self) { fn next_field(&mut self) {
@@ -265,7 +268,7 @@ impl<D: DataProvider> MaskDemoFormEditor<D> {
fn show_mask_details(&mut self) { fn show_mask_details(&mut self) {
let (raw, display, mask_info) = self.get_current_field_info(); let (raw, display, mask_info) = self.get_current_field_info();
self.debug_message = format!("🔍 Field {}: {} | Raw: '{}' Display: '{}'", self.debug_message = format!("🔍 Field {}: {} | Raw: '{}' Display: '{}'",
self.current_field() + 1, mask_info, raw, display); self.current_field() + 1, mask_info, raw, display);
} }
@@ -331,11 +334,11 @@ impl DataProvider for MaskDemoData {
.build()) .build())
} }
1 => { 1 => {
// 📞 Phone (Template) - FIXED: Perfect mask/limit coordination // 📞 Phone (Template) - FIXED: Perfect mask/limit coordination
let phone_template = DisplayMask::new("(###) ###-####", '#') let phone_template = DisplayMask::new("(###) ###-####", '#')
.with_template('_'); .with_template('_');
Some(ValidationConfigBuilder::new() Some(ValidationConfigBuilder::new()
.with_display_mask(phone_template) .with_display_mask(phone_template)
.with_max_length(10) // ✅ CRITICAL: Exactly matches 10 input positions .with_max_length(10) // ✅ CRITICAL: Exactly matches 10 input positions
.build()) .build())
} }
@@ -361,7 +364,7 @@ impl DataProvider for MaskDemoData {
let ssn_mask = DisplayMask::new("XXX-XX-XXXX", 'X'); let ssn_mask = DisplayMask::new("XXX-XX-XXXX", 'X');
Some(ValidationConfigBuilder::new() Some(ValidationConfigBuilder::new()
.with_display_mask(ssn_mask) .with_display_mask(ssn_mask)
.with_max_length(9) // ✅ CRITICAL: Exactly matches 9 input positions .with_max_length(9) // ✅ CRITICAL: Exactly matches 9 input positions
.build()) .build())
} }
6 => { 6 => {
@@ -595,9 +598,9 @@ fn render_mask_status(
}; };
let mask_status = editor.get_mask_status(); let mask_status = editor.get_mask_status();
let status_text = format!("-- {} -- {} | Masks: {} | View: {}", let status_text = format!("-- {} -- {} | Masks: {} | View: {}",
mode_text, mode_text,
editor.debug_message(), editor.debug_message(),
mask_status, mask_status,
if editor.show_raw_data { "RAW" } else { "FORMATTED" }); if editor.show_raw_data { "RAW" } else { "FORMATTED" });
@@ -609,7 +612,7 @@ fn render_mask_status(
// Data comparison showing raw vs display // Data comparison showing raw vs display
let (raw_data, display_data, mask_info) = editor.get_current_field_info(); let (raw_data, display_data, mask_info) = editor.get_current_field_info();
let field_name = editor.data_provider().field_name(editor.current_field()); let field_name = editor.data_provider().field_name(editor.current_field());
let comparison_text = format!( let comparison_text = format!(
"📝 Current Field: {}\n\ "📝 Current Field: {}\n\
🔧 Mask Config: {}\n\ 🔧 Mask Config: {}\n\
@@ -648,7 +651,7 @@ fn render_mask_status(
• Dynamic vs Template modes • Custom separators • Different input chars\n\ • Dynamic vs Template modes • Custom separators • Different input chars\n\
\n\ \n\
Commands: i/a=insert, m=mask details, r=toggle raw/display view\n\ Commands: i/a=insert, m=mask details, r=toggle raw/display view\n\
Movement: hjkl/arrows=move, 0=$=line start/end, Tab=next field, F1=toggle masks\n\ Movement: hjkl/arrows=move, 0/$=line start/end, Tab=next field, F1=toggle masks\n\
?=detailed info, Ctrl+C=quit" ?=detailed info, Ctrl+C=quit"
} }
AppMode::Edit => { AppMode::Edit => {

View File

@@ -1,6 +1,6 @@
/* examples/validation_4.rs /* examples/validation_4.rs
Enhanced Feature 4 Demo: Multiple custom formatters with comprehensive edge cases Enhanced Feature 4 Demo: Multiple custom formatters with comprehensive edge cases
Demonstrates: Demonstrates:
- Multiple formatter types: PSC, Phone, Credit Card, Date - Multiple formatter types: PSC, Phone, Credit Card, Date
- Edge case handling: incomplete input, invalid chars, overflow - Edge case handling: incomplete input, invalid chars, overflow
@@ -53,18 +53,18 @@ impl CustomFormatter for PSCFormatter {
if raw.is_empty() { if raw.is_empty() {
return FormattingResult::success(""); return FormattingResult::success("");
} }
// Validate: only digits allowed // Validate: only digits allowed
if !raw.chars().all(|c| c.is_ascii_digit()) { if !raw.chars().all(|c| c.is_ascii_digit()) {
return FormattingResult::error("PSC must contain only digits"); return FormattingResult::error("PSC must contain only digits");
} }
let len = raw.chars().count(); let len = raw.chars().count();
match len { match len {
0 => FormattingResult::success(""), 0 => FormattingResult::success(""),
1..=3 => FormattingResult::success(raw), 1..=3 => FormattingResult::success(raw),
4 => FormattingResult::warning( 4 => FormattingResult::warning(
format!("{} ", &raw[..3]), format!("{} ", &raw[..3]),
"PSC incomplete (4/5 digits)" "PSC incomplete (4/5 digits)"
), ),
5 => { 5 => {
@@ -88,12 +88,12 @@ impl CustomFormatter for PhoneFormatter {
if raw.is_empty() { if raw.is_empty() {
return FormattingResult::success(""); return FormattingResult::success("");
} }
// Only digits allowed // Only digits allowed
if !raw.chars().all(|c| c.is_ascii_digit()) { if !raw.chars().all(|c| c.is_ascii_digit()) {
return FormattingResult::error("Phone must contain only digits"); return FormattingResult::error("Phone must contain only digits");
} }
let len = raw.chars().count(); let len = raw.chars().count();
match len { match len {
0 => FormattingResult::success(""), 0 => FormattingResult::success(""),
@@ -120,11 +120,11 @@ impl CustomFormatter for CreditCardFormatter {
if raw.is_empty() { if raw.is_empty() {
return FormattingResult::success(""); return FormattingResult::success("");
} }
if !raw.chars().all(|c| c.is_ascii_digit()) { if !raw.chars().all(|c| c.is_ascii_digit()) {
return FormattingResult::error("Card number must contain only digits"); return FormattingResult::error("Card number must contain only digits");
} }
let mut formatted = String::new(); let mut formatted = String::new();
for (i, ch) in raw.chars().enumerate() { for (i, ch) in raw.chars().enumerate() {
if i > 0 && i % 4 == 0 { if i > 0 && i % 4 == 0 {
@@ -132,7 +132,7 @@ impl CustomFormatter for CreditCardFormatter {
} }
formatted.push(ch); formatted.push(ch);
} }
let len = raw.chars().count(); let len = raw.chars().count();
match len { match len {
0..=15 => FormattingResult::warning(formatted, format!("Card incomplete ({}/16 digits)", len)), 0..=15 => FormattingResult::warning(formatted, format!("Card incomplete ({}/16 digits)", len)),
@@ -155,11 +155,11 @@ impl CustomFormatter for DateFormatter {
if raw.is_empty() { if raw.is_empty() {
return FormattingResult::success(""); return FormattingResult::success("");
} }
if !raw.chars().all(|c| c.is_ascii_digit()) { if !raw.chars().all(|c| c.is_ascii_digit()) {
return FormattingResult::error("Date must contain only digits"); return FormattingResult::error("Date must contain only digits");
} }
let len = raw.len(); let len = raw.len();
match len { match len {
0 => FormattingResult::success(""), 0 => FormattingResult::success(""),
@@ -170,11 +170,11 @@ impl CustomFormatter for DateFormatter {
let month = &raw[..2]; let month = &raw[..2];
let day = &raw[2..4]; let day = &raw[2..4];
let year = &raw[4..]; let year = &raw[4..];
// Basic validation // Basic validation
let m: u32 = month.parse().unwrap_or(0); let m: u32 = month.parse().unwrap_or(0);
let d: u32 = day.parse().unwrap_or(0); let d: u32 = day.parse().unwrap_or(0);
if m == 0 || m > 12 { if m == 0 || m > 12 {
FormattingResult::warning( FormattingResult::warning(
format!("{}/{}/{}", month, day, year), format!("{}/{}/{}", month, day, year),
@@ -217,15 +217,15 @@ impl DataProvider for MultiFormatterDemoData {
fn field_count(&self) -> usize { fn field_count(&self) -> usize {
self.fields.len() self.fields.len()
} }
fn field_name(&self, index: usize) -> &str { fn field_name(&self, index: usize) -> &str {
&self.fields[index].0 &self.fields[index].0
} }
fn field_value(&self, index: usize) -> &str { fn field_value(&self, index: usize) -> &str {
&self.fields[index].1 &self.fields[index].1
} }
fn set_field_value(&mut self, index: usize, value: String) { fn set_field_value(&mut self, index: usize, value: String) {
self.fields[index].1 = value; self.fields[index].1 = value;
} }
@@ -288,7 +288,7 @@ impl<D: DataProvider> EnhancedDemoEditor<D> {
match self.editor.current_field() { match self.editor.current_field() {
0 => "PSC", 0 => "PSC",
1 => "Phone", 1 => "Phone",
2 => "Credit Card", 2 => "Credit Card",
3 => "Date", 3 => "Date",
_ => "Plain Text", _ => "Plain Text",
} }
@@ -320,16 +320,16 @@ impl<D: DataProvider> EnhancedDemoEditor<D> {
// Edge cases // Edge cases
vec!["00000", "0000000000", "0000000000000000", "99", "13012024", ""], vec!["00000", "0000000000", "0000000000000000", "99", "13012024", ""],
]; ];
self.example_mode = (self.example_mode + 1) % examples.len(); self.example_mode = (self.example_mode + 1) % examples.len();
let current_examples = &examples[self.example_mode]; let current_examples = &examples[self.example_mode];
for (i, example) in current_examples.iter().enumerate() { for (i, example) in current_examples.iter().enumerate() {
if i < self.editor.data_provider().field_count() { if i < self.editor.data_provider().field_count() {
self.editor.data_provider_mut().set_field_value(i, example.to_string()); self.editor.data_provider_mut().set_field_value(i, example.to_string());
} }
} }
let mode_names = ["Valid Examples", "Incomplete Input", "Invalid Characters", "Edge Cases"]; let mode_names = ["Valid Examples", "Incomplete Input", "Invalid Characters", "Edge Cases"];
self.debug_message = format!("📋 Loaded: {}", mode_names[self.example_mode]); self.debug_message = format!("📋 Loaded: {}", mode_names[self.example_mode]);
} }
@@ -364,9 +364,10 @@ impl<D: DataProvider> EnhancedDemoEditor<D> {
} }
fn get_current_field_analysis(&self) -> (String, String, String, Option<String>) { fn get_current_field_analysis(&self) -> (String, String, String, Option<String>) {
let raw = self.editor.current_text(); let field_index = self.editor.current_field();
let raw = self.editor.data_provider().field_value(field_index);
let display = self.editor.current_display_text(); let display = self.editor.current_display_text();
let status = if raw == display { let status = if raw == display {
if self.has_formatter() { if self.has_formatter() {
if self.mode() == AppMode::Edit { if self.mode() == AppMode::Edit {
@@ -445,9 +446,10 @@ impl<D: DataProvider> EnhancedDemoEditor<D> {
let raw_pos = self.editor.cursor_position(); let raw_pos = self.editor.cursor_position();
let display_pos = self.editor.display_cursor_position(); let display_pos = self.editor.display_cursor_position();
let raw = self.editor.current_text(); let field_index = self.editor.current_field();
let raw = self.editor.data_provider().field_value(field_index);
let display = self.editor.current_display_text(); let display = self.editor.current_display_text();
if raw_pos != display_pos { if raw_pos != display_pos {
self.debug_message = format!( self.debug_message = format!(
"🗺️ Position mapping: Raw[{}]='{}' ↔ Display[{}]='{}'", "🗺️ Position mapping: Raw[{}]='{}' ↔ Display[{}]='{}'",
@@ -468,7 +470,7 @@ impl<D: DataProvider> EnhancedDemoEditor<D> {
fn data_provider(&self) -> &D { self.editor.data_provider() } fn data_provider(&self) -> &D { self.editor.data_provider() }
fn data_provider_mut(&mut self) -> &mut D { self.editor.data_provider_mut() } fn data_provider_mut(&mut self) -> &mut D { self.editor.data_provider_mut() }
fn ui_state(&self) -> &canvas::EditorState { self.editor.ui_state() } fn ui_state(&self) -> &canvas::EditorState { self.editor.ui_state() }
fn move_up(&mut self) { let _ = self.editor.move_up(); } fn move_up(&mut self) { let _ = self.editor.move_up(); }
fn move_down(&mut self) { let _ = self.editor.move_down(); } fn move_down(&mut self) { let _ = self.editor.move_down(); }
fn move_left(&mut self) { let _ = self.editor.move_left(); } fn move_left(&mut self) { let _ = self.editor.move_left(); }
@@ -488,7 +490,7 @@ fn handle_key_press(
let mode = editor.mode(); let mode = editor.mode();
// Quit // Quit
if matches!(key, KeyCode::F(10)) || if matches!(key, KeyCode::F(10)) ||
(key == KeyCode::Char('q') && modifiers.contains(KeyModifiers::CONTROL)) || (key == KeyCode::Char('q') && modifiers.contains(KeyModifiers::CONTROL)) ||
(key == KeyCode::Char('c') && modifiers.contains(KeyModifiers::CONTROL)) { (key == KeyCode::Char('c') && modifiers.contains(KeyModifiers::CONTROL)) {
return Ok(false); return Ok(false);
@@ -530,7 +532,7 @@ fn handle_key_press(
let (raw, display, status, warning) = editor.get_current_field_analysis(); 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!( editor.debug_message = format!(
"🔍 Field {}: {} | Raw: '{}' | Display: '{}'{}", "🔍 Field {}: {} | Raw: '{}' | Display: '{}'{}",
editor.current_field() + 1, status, raw, display, warning_text editor.current_field() + 1, status, raw, display, warning_text
); );
}, },
@@ -618,7 +620,7 @@ fn render_enhanced_status(
let (raw, display, status, warning) = editor.get_current_field_analysis(); let (raw, display, status, warning) = editor.get_current_field_analysis();
let field_name = editor.data_provider().field_name(editor.current_field()); let field_name = editor.data_provider().field_name(editor.current_field());
let field_type = editor.current_field_type(); let field_type = editor.current_field_type();
let mut analysis_lines = vec![ let mut analysis_lines = vec![
format!("📝 Current: {} ({})", field_name, field_type), format!("📝 Current: {} ({})", field_name, field_type),
format!("🔧 Status: {}", status), format!("🔧 Status: {}", status),