compiled examples
This commit is contained in:
@@ -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)?;
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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 => {
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user