better example for feature2 being implemented and integrated into the codebase
This commit is contained in:
@@ -1,16 +1,20 @@
|
|||||||
// examples/validation_patterns_tui.rs
|
// examples/validation_2.rs
|
||||||
//! TUI Example demonstrating position-based pattern filtering
|
//! Advanced TUI Example demonstrating complex pattern filtering edge cases
|
||||||
//!
|
//!
|
||||||
//! Run with: cargo run --example validation_patterns_tui --features "validation,gui"
|
//! This example showcases the full potential of the pattern validation system
|
||||||
|
//! with creative real-world scenarios and edge cases.
|
||||||
|
//!
|
||||||
|
//! Run with: cargo run --example validation_advanced_patterns --features "validation,gui"
|
||||||
|
|
||||||
// REQUIRE validation and gui features - example won't compile without them
|
// REQUIRE validation and gui features
|
||||||
#[cfg(not(all(feature = "validation", feature = "gui")))]
|
#[cfg(not(all(feature = "validation", feature = "gui")))]
|
||||||
compile_error!(
|
compile_error!(
|
||||||
"This example requires the 'validation' and 'gui' features. \
|
"This example requires the 'validation' and 'gui' features. \
|
||||||
Run with: cargo run --example validation_patterns_tui --features \"validation,gui\""
|
Run with: cargo run --example validation_advanced_patterns --features \"validation,gui\""
|
||||||
);
|
);
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::sync::Arc;
|
||||||
use canvas::ValidationResult;
|
use canvas::ValidationResult;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{
|
event::{
|
||||||
@@ -39,8 +43,8 @@ use canvas::{
|
|||||||
ValidationConfig, ValidationConfigBuilder, PatternFilters, PositionFilter, PositionRange, CharacterFilter,
|
ValidationConfig, ValidationConfigBuilder, PatternFilters, PositionFilter, PositionRange, CharacterFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enhanced FormEditor for pattern validation demonstration
|
// Enhanced FormEditor wrapper (keeping the same structure as before)
|
||||||
struct PatternValidationFormEditor<D: DataProvider> {
|
struct AdvancedPatternFormEditor<D: DataProvider> {
|
||||||
editor: FormEditor<D>,
|
editor: FormEditor<D>,
|
||||||
debug_message: String,
|
debug_message: String,
|
||||||
command_buffer: String,
|
command_buffer: String,
|
||||||
@@ -49,16 +53,14 @@ struct PatternValidationFormEditor<D: DataProvider> {
|
|||||||
block_reason: Option<String>,
|
block_reason: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: DataProvider> PatternValidationFormEditor<D> {
|
impl<D: DataProvider> AdvancedPatternFormEditor<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
|
|
||||||
editor.set_validation_enabled(true);
|
editor.set_validation_enabled(true);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
editor,
|
editor,
|
||||||
debug_message: "🔍 Pattern Validation Demo - Try typing in different fields!".to_string(),
|
debug_message: "🚀 Advanced Pattern Validation - Showcasing edge cases and complex patterns!".to_string(),
|
||||||
command_buffer: String::new(),
|
command_buffer: String::new(),
|
||||||
validation_enabled: true,
|
validation_enabled: true,
|
||||||
field_switch_blocked: false,
|
field_switch_blocked: false,
|
||||||
@@ -66,95 +68,52 @@ impl<D: DataProvider> PatternValidationFormEditor<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === COMMAND BUFFER HANDLING ===
|
// ... (keeping all the same methods as before for brevity)
|
||||||
fn clear_command_buffer(&mut self) {
|
// [All the previous methods: clear_command_buffer, add_to_command_buffer, etc.]
|
||||||
self.command_buffer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_to_command_buffer(&mut self, ch: char) {
|
fn clear_command_buffer(&mut self) { self.command_buffer.clear(); }
|
||||||
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 has_pending_command(&self) -> bool { !self.command_buffer.is_empty() }
|
||||||
|
|
||||||
fn get_command_buffer(&self) -> &str {
|
|
||||||
&self.command_buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_pending_command(&self) -> bool {
|
|
||||||
!self.command_buffer.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
// === VALIDATION CONTROL ===
|
|
||||||
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 = "✅ Pattern Validation ENABLED".to_string();
|
self.debug_message = "✅ Advanced Pattern Validation ENABLED".to_string();
|
||||||
} else {
|
} else {
|
||||||
self.debug_message = "❌ Pattern Validation DISABLED".to_string();
|
self.debug_message = "❌ Advanced Pattern Validation DISABLED".to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === MOVEMENT ===
|
fn move_left(&mut self) { self.editor.move_left(); self.field_switch_blocked = false; self.block_reason = None; }
|
||||||
fn move_left(&mut self) {
|
fn move_right(&mut self) { self.editor.move_right(); self.field_switch_blocked = false; self.block_reason = None; }
|
||||||
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_up(&mut self) {
|
fn move_up(&mut self) {
|
||||||
match self.editor.move_up() {
|
match self.editor.move_up() {
|
||||||
Ok(()) => {
|
Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; }
|
||||||
self.update_field_validation_status();
|
Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("🚫 Field switch blocked: {}", e); }
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_down(&mut self) {
|
fn move_down(&mut self) {
|
||||||
match self.editor.move_down() {
|
match self.editor.move_down() {
|
||||||
Ok(()) => {
|
Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; }
|
||||||
self.update_field_validation_status();
|
Err(e) => { self.field_switch_blocked = true; self.block_reason = Some(e.to_string()); self.debug_message = format!("🚫 Field switch blocked: {}", e); }
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_line_start(&mut self) {
|
fn move_line_start(&mut self) { self.editor.move_line_start(); }
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// === MODE TRANSITIONS ===
|
|
||||||
fn enter_edit_mode(&mut self) {
|
fn enter_edit_mode(&mut self) {
|
||||||
self.editor.enter_edit_mode();
|
self.editor.enter_edit_mode();
|
||||||
self.debug_message = "✏️ INSERT MODE - Type to test pattern validation".to_string();
|
self.debug_message = "✏️ INSERT MODE - Testing advanced pattern validation".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_append_mode(&mut self) {
|
fn enter_append_mode(&mut self) {
|
||||||
self.editor.enter_append_mode();
|
self.editor.enter_append_mode();
|
||||||
self.debug_message = "✏️ INSERT (append) - Pattern validation active".to_string();
|
self.debug_message = "✏️ INSERT (append) - Advanced patterns active".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit_edit_mode(&mut self) {
|
fn exit_edit_mode(&mut self) {
|
||||||
@@ -166,253 +125,271 @@ impl<D: DataProvider> PatternValidationFormEditor<D> {
|
|||||||
fn insert_char(&mut self, ch: char) -> anyhow::Result<()> {
|
fn insert_char(&mut self, ch: char) -> anyhow::Result<()> {
|
||||||
let result = self.editor.insert_char(ch);
|
let result = self.editor.insert_char(ch);
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
// Show real-time validation feedback
|
|
||||||
if let Some(validation_result) = self.editor.current_field_validation() {
|
if let Some(validation_result) = self.editor.current_field_validation() {
|
||||||
match validation_result {
|
match validation_result {
|
||||||
ValidationResult::Valid => {
|
ValidationResult::Valid => { self.debug_message = "✅ Character accepted".to_string(); }
|
||||||
self.debug_message = "✅ Valid character".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!("❌ Error: {}", message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(result?)
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
// === DELETE OPERATIONS ===
|
|
||||||
fn delete_backward(&mut self) -> anyhow::Result<()> {
|
fn delete_backward(&mut self) -> anyhow::Result<()> {
|
||||||
let result = self.editor.delete_backward();
|
let result = self.editor.delete_backward();
|
||||||
if result.is_ok() {
|
if result.is_ok() { self.debug_message = "⌫ Character deleted".to_string(); }
|
||||||
self.debug_message = "⌫ Deleted character".to_string();
|
|
||||||
}
|
|
||||||
Ok(result?)
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_forward(&mut self) -> anyhow::Result<()> {
|
fn delete_forward(&mut self) -> anyhow::Result<()> {
|
||||||
let result = self.editor.delete_forward();
|
let result = self.editor.delete_forward();
|
||||||
if result.is_ok() {
|
if result.is_ok() { self.debug_message = "⌦ Character deleted".to_string(); }
|
||||||
self.debug_message = "⌦ Deleted character".to_string();
|
|
||||||
}
|
|
||||||
Ok(result?)
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
// === DELEGATE TO ORIGINAL EDITOR ===
|
// Delegate methods
|
||||||
fn current_field(&self) -> usize {
|
fn current_field(&self) -> usize { self.editor.current_field() }
|
||||||
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 cursor_position(&self) -> usize {
|
fn data_provider(&self) -> &D { self.editor.data_provider() }
|
||||||
self.editor.cursor_position()
|
fn ui_state(&self) -> &canvas::EditorState { self.editor.ui_state() }
|
||||||
}
|
fn set_mode(&mut self, mode: AppMode) { self.editor.set_mode(mode); }
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_field(&mut self) {
|
fn next_field(&mut self) {
|
||||||
match self.editor.next_field() {
|
match self.editor.next_field() {
|
||||||
Ok(()) => {
|
Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; }
|
||||||
self.update_field_validation_status();
|
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.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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prev_field(&mut self) {
|
fn prev_field(&mut self) {
|
||||||
match self.editor.prev_field() {
|
match self.editor.prev_field() {
|
||||||
Ok(()) => {
|
Ok(()) => { self.update_field_validation_status(); self.field_switch_blocked = false; self.block_reason = None; }
|
||||||
self.update_field_validation_status();
|
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.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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === STATUS AND DEBUG ===
|
fn set_debug_message(&mut self, msg: String) { self.debug_message = msg; }
|
||||||
fn set_debug_message(&mut self, msg: String) {
|
fn debug_message(&self) -> &str { &self.debug_message }
|
||||||
self.debug_message = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn debug_message(&self) -> &str {
|
|
||||||
&self.debug_message
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_field_validation_status(&mut self) {
|
fn update_field_validation_status(&mut self) {
|
||||||
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 => { self.debug_message = format!("Field {}: ✅ Pattern valid", self.editor.current_field() + 1); }
|
||||||
self.debug_message = format!("Field {}: ✅ Valid", self.editor.current_field() + 1);
|
ValidationResult::Warning { message } => { self.debug_message = format!("Field {}: ⚠️ {}", self.editor.current_field() + 1, message); }
|
||||||
|
ValidationResult::Error { message } => { self.debug_message = format!("Field {}: ❌ {}", self.editor.current_field() + 1, message); }
|
||||||
}
|
}
|
||||||
ValidationResult::Warning { message } => {
|
|
||||||
self.debug_message = format!("Field {}: ⚠️ {}", self.editor.current_field() + 1, message);
|
|
||||||
}
|
|
||||||
ValidationResult::Error { message } => {
|
|
||||||
self.debug_message = format!("Field {}: ❌ {}", self.editor.current_field() + 1, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.debug_message = format!("Field {}: 🔍 Not validated yet", self.editor.current_field() + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_validation_status(&self) -> String {
|
fn get_validation_status(&self) -> String {
|
||||||
if !self.validation_enabled {
|
if !self.validation_enabled { return "❌ DISABLED".to_string(); }
|
||||||
return "❌ DISABLED".to_string();
|
if self.field_switch_blocked { return "🚫 SWITCH BLOCKED".to_string(); }
|
||||||
}
|
|
||||||
|
|
||||||
if self.field_switch_blocked {
|
|
||||||
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)
|
else if summary.has_warnings() { format!("⚠️ {} WARNINGS", summary.warning_fields) }
|
||||||
} else if summary.has_warnings() {
|
else if summary.validated_fields > 0 { format!("✅ {} VALID", summary.valid_fields) }
|
||||||
format!("⚠️ {} WARNINGS", summary.warning_fields)
|
else { "🔍 READY".to_string() }
|
||||||
} else if summary.validated_fields > 0 {
|
|
||||||
format!("✅ {} VALID", summary.valid_fields)
|
|
||||||
} else {
|
|
||||||
"🔍 READY".to_string()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demo form with pattern-based validation
|
// Advanced demo form with creative and edge-case-heavy validation patterns
|
||||||
struct PatternValidationData {
|
struct AdvancedPatternData {
|
||||||
fields: Vec<(String, String)>,
|
fields: Vec<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PatternValidationData {
|
impl AdvancedPatternData {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
fields: vec![
|
fields: vec![
|
||||||
("🚗 License Plate (AB123)".to_string(), "".to_string()),
|
("🕐 Time (HH:MM) - 24hr format".to_string(), "".to_string()),
|
||||||
("📞 Phone (123-456-7890)".to_string(), "".to_string()),
|
("🎨 Hex Color (#RRGGBB) - Web colors".to_string(), "".to_string()),
|
||||||
("💳 Credit Card (1234-5678-9012-3456)".to_string(), "".to_string()),
|
("🌐 IPv4 (XXX.XXX.XXX.XXX) - Network address".to_string(), "".to_string()),
|
||||||
("🆔 Custom ID (AB123def)".to_string(), "".to_string()),
|
("🏷️ Product Code (ABC-123-XYZ) - Mixed format".to_string(), "".to_string()),
|
||||||
|
("📅 Date Code (2024W15) - Year + Week".to_string(), "".to_string()),
|
||||||
|
("🔢 Binary (101010) - Only 0s and 1s".to_string(), "".to_string()),
|
||||||
|
("🎯 Complex ID (A1-B2C-3D4E) - Multi-rule".to_string(), "".to_string()),
|
||||||
|
("🚀 Custom Pattern - Advanced logic".to_string(), "".to_string()),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataProvider for PatternValidationData {
|
impl DataProvider for AdvancedPatternData {
|
||||||
fn field_count(&self) -> usize {
|
fn field_count(&self) -> usize { self.fields.len() }
|
||||||
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 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pattern validation configuration per field
|
|
||||||
fn validation_config(&self, field_index: usize) -> Option<ValidationConfig> {
|
fn validation_config(&self, field_index: usize) -> Option<ValidationConfig> {
|
||||||
match field_index {
|
match field_index {
|
||||||
0 => {
|
0 => {
|
||||||
// License plate: AB123 (2 letters, 3 numbers)
|
// 🕐 Time (HH:MM) - Hours 00-23, Minutes 00-59
|
||||||
let license_plate_pattern = PatternFilters::new()
|
// This showcases: Multiple position ranges, exact character matching, custom validation
|
||||||
|
let time_pattern = PatternFilters::new()
|
||||||
.add_filter(PositionFilter::new(
|
.add_filter(PositionFilter::new(
|
||||||
PositionRange::Range(0, 1),
|
PositionRange::Multiple(vec![0, 1, 3, 4]), // Hours and minutes positions
|
||||||
CharacterFilter::Alphabetic,
|
CharacterFilter::Numeric,
|
||||||
))
|
))
|
||||||
.add_filter(PositionFilter::new(
|
.add_filter(PositionFilter::new(
|
||||||
PositionRange::Range(2, 4),
|
PositionRange::Single(2), // Colon separator
|
||||||
CharacterFilter::Numeric,
|
CharacterFilter::Exact(':'),
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(ValidationConfigBuilder::new()
|
Some(ValidationConfigBuilder::new()
|
||||||
.with_pattern_filters(license_plate_pattern)
|
.with_pattern_filters(time_pattern)
|
||||||
|
.with_max_length(5) // HH:MM = 5 characters
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
// Phone number: 123-456-7890
|
// 🎨 Hex Color (#RRGGBB) - Web color format
|
||||||
let phone_pattern = PatternFilters::new()
|
// This showcases: OneOf filter with hex digits, exact character at start
|
||||||
|
let hex_digits = vec!['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'];
|
||||||
|
let hex_color_pattern = PatternFilters::new()
|
||||||
.add_filter(PositionFilter::new(
|
.add_filter(PositionFilter::new(
|
||||||
PositionRange::Multiple(vec![0,1,2,4,5,6,8,9,10,11]),
|
PositionRange::Single(0), // Hash symbol
|
||||||
CharacterFilter::Numeric,
|
CharacterFilter::Exact('#'),
|
||||||
))
|
))
|
||||||
.add_filter(PositionFilter::new(
|
.add_filter(PositionFilter::new(
|
||||||
PositionRange::Multiple(vec![3, 7]),
|
PositionRange::Range(1, 6), // 6 hex digits for RGB
|
||||||
CharacterFilter::Exact('-'),
|
CharacterFilter::OneOf(hex_digits),
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(ValidationConfigBuilder::new()
|
Some(ValidationConfigBuilder::new()
|
||||||
.with_pattern_filters(phone_pattern)
|
.with_pattern_filters(hex_color_pattern)
|
||||||
|
.with_max_length(7) // #RRGGBB = 7 characters
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
// Credit card: 1234-5678-9012-3456
|
// 🌐 IPv4 Address (XXX.XXX.XXX.XXX) - Network address
|
||||||
let credit_card_pattern = PatternFilters::new()
|
// This showcases: Complex pattern with dots at specific positions
|
||||||
|
let ipv4_pattern = PatternFilters::new()
|
||||||
.add_filter(PositionFilter::new(
|
.add_filter(PositionFilter::new(
|
||||||
PositionRange::Multiple(vec![0,1,2,3,5,6,7,8,10,11,12,13,15,16,17,18]),
|
PositionRange::Multiple(vec![3, 7, 11]), // Dots at specific positions
|
||||||
CharacterFilter::Numeric,
|
CharacterFilter::Exact('.'),
|
||||||
))
|
))
|
||||||
.add_filter(PositionFilter::new(
|
.add_filter(PositionFilter::new(
|
||||||
PositionRange::Multiple(vec![4, 9, 14]),
|
PositionRange::Multiple(vec![0,1,2,4,5,6,8,9,10,12,13,14]), // Number positions
|
||||||
CharacterFilter::Exact('-'),
|
CharacterFilter::Numeric,
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(ValidationConfigBuilder::new()
|
Some(ValidationConfigBuilder::new()
|
||||||
.with_pattern_filters(credit_card_pattern)
|
.with_pattern_filters(ipv4_pattern)
|
||||||
|
.with_max_length(15) // XXX.XXX.XXX.XXX = up to 15 chars
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
// Custom ID: First 2 letters, rest alphanumeric
|
// 🏷️ Product Code (ABC-123-XYZ) - Mixed format sections
|
||||||
let custom_id_pattern = PatternFilters::new()
|
// This showcases: Different rules for different sections
|
||||||
|
let product_code_pattern = PatternFilters::new()
|
||||||
.add_filter(PositionFilter::new(
|
.add_filter(PositionFilter::new(
|
||||||
PositionRange::Range(0, 1),
|
PositionRange::Range(0, 2), // First 3 positions: letters
|
||||||
CharacterFilter::Alphabetic,
|
CharacterFilter::Alphabetic,
|
||||||
))
|
))
|
||||||
.add_filter(PositionFilter::new(
|
.add_filter(PositionFilter::new(
|
||||||
PositionRange::From(2),
|
PositionRange::Multiple(vec![3, 7]), // Dashes
|
||||||
CharacterFilter::Alphanumeric,
|
CharacterFilter::Exact('-'),
|
||||||
|
))
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::Range(4, 6), // Middle 3 positions: numbers
|
||||||
|
CharacterFilter::Numeric,
|
||||||
|
))
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::Range(8, 10), // Last 3 positions: letters
|
||||||
|
CharacterFilter::Alphabetic,
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(ValidationConfigBuilder::new()
|
Some(ValidationConfigBuilder::new()
|
||||||
.with_pattern_filters(custom_id_pattern)
|
.with_pattern_filters(product_code_pattern)
|
||||||
|
.with_max_length(11) // ABC-123-XYZ = 11 characters
|
||||||
|
.build())
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
// 📅 Date Code (2024W15) - Year + Week format
|
||||||
|
// This showcases: From position filtering and mixed patterns
|
||||||
|
let date_code_pattern = PatternFilters::new()
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::Range(0, 3), // Year: 4 digits
|
||||||
|
CharacterFilter::Numeric,
|
||||||
|
))
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::Single(4), // Week indicator
|
||||||
|
CharacterFilter::Exact('W'),
|
||||||
|
))
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::From(5), // Week number: rest are digits
|
||||||
|
CharacterFilter::Numeric,
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(ValidationConfigBuilder::new()
|
||||||
|
.with_pattern_filters(date_code_pattern)
|
||||||
|
.with_max_length(7) // 2024W15 = 7 characters
|
||||||
|
.build())
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
// 🔢 Binary (101010) - Only 0s and 1s
|
||||||
|
// This showcases: OneOf filter with limited character set
|
||||||
|
let binary_pattern = PatternFilters::new()
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::From(0), // All positions
|
||||||
|
CharacterFilter::OneOf(vec!['0', '1']),
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(ValidationConfigBuilder::new()
|
||||||
|
.with_pattern_filters(binary_pattern)
|
||||||
|
.with_max_length(16) // Allow up to 16 binary digits
|
||||||
|
.build())
|
||||||
|
}
|
||||||
|
6 => {
|
||||||
|
// 🎯 Complex ID (A1-B2C-3D4E) - Multiple overlapping rules
|
||||||
|
// This showcases: Complex overlapping patterns and edge cases
|
||||||
|
let complex_id_pattern = PatternFilters::new()
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::Multiple(vec![0, 3, 6, 8]), // Letter positions
|
||||||
|
CharacterFilter::Alphabetic,
|
||||||
|
))
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::Multiple(vec![1, 4, 7, 9]), // Number positions
|
||||||
|
CharacterFilter::Numeric,
|
||||||
|
))
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::Multiple(vec![2, 5]), // Dashes
|
||||||
|
CharacterFilter::Exact('-'),
|
||||||
|
))
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::Single(5), // Special case: override dash with letter C
|
||||||
|
CharacterFilter::Alphabetic, // This creates an interesting edge case
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(ValidationConfigBuilder::new()
|
||||||
|
.with_pattern_filters(complex_id_pattern)
|
||||||
|
.with_max_length(10) // A1-B2C-3D4E = 10 characters
|
||||||
|
.build())
|
||||||
|
}
|
||||||
|
7 => {
|
||||||
|
// 🚀 Custom Pattern - Advanced logic with custom function
|
||||||
|
// This showcases: Custom validation function for complex rules
|
||||||
|
let custom_pattern = PatternFilters::new()
|
||||||
|
.add_filter(PositionFilter::new(
|
||||||
|
PositionRange::From(0),
|
||||||
|
CharacterFilter::Custom(Arc::new(|c| {
|
||||||
|
// Advanced rule: Alternating vowels and consonants!
|
||||||
|
// Even positions (0,2,4...): vowels (a,e,i,o,u)
|
||||||
|
// Odd positions (1,3,5...): consonants
|
||||||
|
let vowels = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'];
|
||||||
|
|
||||||
|
// For demo purposes, we'll just accept alphabetic characters
|
||||||
|
// In real usage, you'd implement the alternating logic based on position
|
||||||
|
c.is_alphabetic()
|
||||||
|
})),
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(ValidationConfigBuilder::new()
|
||||||
|
.with_pattern_filters(custom_pattern)
|
||||||
|
.with_max_length(12) // Allow up to 12 characters
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -420,11 +397,11 @@ impl DataProvider for PatternValidationData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle key presses with pattern validation commands
|
// Key handling (same structure as before)
|
||||||
fn handle_key_press(
|
fn handle_key_press(
|
||||||
key: KeyCode,
|
key: KeyCode,
|
||||||
modifiers: KeyModifiers,
|
modifiers: KeyModifiers,
|
||||||
editor: &mut PatternValidationFormEditor<PatternValidationData>,
|
editor: &mut AdvancedPatternFormEditor<AdvancedPatternData>,
|
||||||
) -> anyhow::Result<bool> {
|
) -> anyhow::Result<bool> {
|
||||||
let mode = editor.mode();
|
let mode = editor.mode();
|
||||||
|
|
||||||
@@ -437,99 +414,50 @@ fn handle_key_press(
|
|||||||
}
|
}
|
||||||
|
|
||||||
match (mode, key, modifiers) {
|
match (mode, key, modifiers) {
|
||||||
// === MODE TRANSITIONS ===
|
// Mode transitions
|
||||||
(AppMode::ReadOnly, KeyCode::Char('i'), _) => {
|
(AppMode::ReadOnly, KeyCode::Char('i'), _) => { editor.enter_edit_mode(); editor.clear_command_buffer(); }
|
||||||
editor.enter_edit_mode();
|
(AppMode::ReadOnly, KeyCode::Char('a'), _) => { editor.enter_append_mode(); editor.clear_command_buffer(); }
|
||||||
editor.clear_command_buffer();
|
(AppMode::ReadOnly, KeyCode::Char('A'), _) => { editor.move_line_end(); editor.enter_edit_mode(); editor.clear_command_buffer(); }
|
||||||
}
|
(_, KeyCode::Esc, _) => { if mode == AppMode::Edit { editor.exit_edit_mode(); } else { editor.clear_command_buffer(); } }
|
||||||
(AppMode::ReadOnly, KeyCode::Char('a'), _) => {
|
|
||||||
editor.enter_append_mode();
|
|
||||||
editor.clear_command_buffer();
|
|
||||||
}
|
|
||||||
(AppMode::ReadOnly, KeyCode::Char('A'), _) => {
|
|
||||||
editor.move_line_end();
|
|
||||||
editor.enter_edit_mode();
|
|
||||||
editor.clear_command_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Escape: Exit edit mode
|
// Validation commands
|
||||||
(_, KeyCode::Esc, _) => {
|
(AppMode::ReadOnly, KeyCode::F(1), _) => { editor.toggle_validation(); }
|
||||||
if mode == AppMode::Edit {
|
|
||||||
editor.exit_edit_mode();
|
|
||||||
} else {
|
|
||||||
editor.clear_command_buffer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === VALIDATION COMMANDS ===
|
// Movement in ReadOnly mode
|
||||||
(AppMode::ReadOnly, KeyCode::F(1), _) => {
|
(AppMode::ReadOnly, KeyCode::Char('h'), _) | (AppMode::ReadOnly, KeyCode::Left, _) => { editor.move_left(); editor.clear_command_buffer(); }
|
||||||
editor.toggle_validation();
|
(AppMode::ReadOnly, KeyCode::Char('l'), _) | (AppMode::ReadOnly, KeyCode::Right, _) => { editor.move_right(); editor.clear_command_buffer(); }
|
||||||
}
|
(AppMode::ReadOnly, KeyCode::Char('j'), _) | (AppMode::ReadOnly, KeyCode::Down, _) => { editor.move_down(); editor.clear_command_buffer(); }
|
||||||
|
(AppMode::ReadOnly, KeyCode::Char('k'), _) | (AppMode::ReadOnly, KeyCode::Up, _) => { editor.move_up(); editor.clear_command_buffer(); }
|
||||||
|
|
||||||
// === MOVEMENT ===
|
// Movement in Edit mode
|
||||||
(AppMode::ReadOnly, KeyCode::Char('h'), _) | (AppMode::ReadOnly, KeyCode::Left, _) => {
|
(AppMode::Edit, KeyCode::Left, _) => { editor.move_left(); }
|
||||||
editor.move_left();
|
(AppMode::Edit, KeyCode::Right, _) => { editor.move_right(); }
|
||||||
editor.clear_command_buffer();
|
(AppMode::Edit, KeyCode::Up, _) => { editor.move_up(); }
|
||||||
}
|
(AppMode::Edit, KeyCode::Down, _) => { editor.move_down(); }
|
||||||
(AppMode::ReadOnly, KeyCode::Char('l'), _) | (AppMode::ReadOnly, KeyCode::Right, _) => {
|
|
||||||
editor.move_right();
|
|
||||||
editor.clear_command_buffer();
|
|
||||||
}
|
|
||||||
(AppMode::ReadOnly, KeyCode::Char('j'), _) | (AppMode::ReadOnly, KeyCode::Down, _) => {
|
|
||||||
editor.move_down();
|
|
||||||
editor.clear_command_buffer();
|
|
||||||
}
|
|
||||||
(AppMode::ReadOnly, KeyCode::Char('k'), _) | (AppMode::ReadOnly, KeyCode::Up, _) => {
|
|
||||||
editor.move_up();
|
|
||||||
editor.clear_command_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
// === EDIT MODE MOVEMENT ===
|
// Delete operations
|
||||||
(AppMode::Edit, KeyCode::Left, _) => {
|
(AppMode::Edit, KeyCode::Backspace, _) => { editor.delete_backward()?; }
|
||||||
editor.move_left();
|
(AppMode::Edit, KeyCode::Delete, _) => { editor.delete_forward()?; }
|
||||||
}
|
|
||||||
(AppMode::Edit, KeyCode::Right, _) => {
|
|
||||||
editor.move_right();
|
|
||||||
}
|
|
||||||
(AppMode::Edit, KeyCode::Up, _) => {
|
|
||||||
editor.move_up();
|
|
||||||
}
|
|
||||||
(AppMode::Edit, KeyCode::Down, _) => {
|
|
||||||
editor.move_down();
|
|
||||||
}
|
|
||||||
|
|
||||||
// === DELETE OPERATIONS ===
|
// Tab navigation
|
||||||
(AppMode::Edit, KeyCode::Backspace, _) => {
|
(_, KeyCode::Tab, _) => { editor.next_field(); }
|
||||||
editor.delete_backward()?;
|
(_, KeyCode::BackTab, _) => { editor.prev_field(); }
|
||||||
}
|
|
||||||
(AppMode::Edit, KeyCode::Delete, _) => {
|
|
||||||
editor.delete_forward()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === TAB NAVIGATION ===
|
// Character input
|
||||||
(_, KeyCode::Tab, _) => {
|
|
||||||
editor.next_field();
|
|
||||||
}
|
|
||||||
(_, KeyCode::BackTab, _) => {
|
|
||||||
editor.prev_field();
|
|
||||||
}
|
|
||||||
|
|
||||||
// === CHARACTER INPUT ===
|
|
||||||
(AppMode::Edit, KeyCode::Char(c), m) if !m.contains(KeyModifiers::CONTROL) => {
|
(AppMode::Edit, KeyCode::Char(c), m) if !m.contains(KeyModifiers::CONTROL) => {
|
||||||
editor.insert_char(c)?;
|
editor.insert_char(c)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === DEBUG/INFO COMMANDS ===
|
// Debug info
|
||||||
(AppMode::ReadOnly, KeyCode::Char('?'), _) => {
|
(AppMode::ReadOnly, KeyCode::Char('?'), _) => {
|
||||||
let summary = editor.editor.validation_summary();
|
let summary = editor.editor.validation_summary();
|
||||||
editor.set_debug_message(format!(
|
editor.set_debug_message(format!(
|
||||||
"Field {}/{}, Pos {}, Mode: {:?}, Validation: {} fields configured, {} validated",
|
"Field {}/{}, Pos {}, Mode: {:?}, Advanced patterns: {} configured",
|
||||||
editor.current_field() + 1,
|
editor.current_field() + 1,
|
||||||
editor.data_provider().field_count(),
|
editor.data_provider().field_count(),
|
||||||
editor.cursor_position(),
|
editor.cursor_position(),
|
||||||
editor.mode(),
|
editor.mode(),
|
||||||
summary.total_fields,
|
summary.total_fields
|
||||||
summary.validated_fields
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +474,7 @@ fn handle_key_press(
|
|||||||
|
|
||||||
fn run_app<B: Backend>(
|
fn run_app<B: Backend>(
|
||||||
terminal: &mut Terminal<B>,
|
terminal: &mut Terminal<B>,
|
||||||
mut editor: PatternValidationFormEditor<PatternValidationData>,
|
mut editor: AdvancedPatternFormEditor<AdvancedPatternData>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
loop {
|
loop {
|
||||||
terminal.draw(|f| ui(f, &editor))?;
|
terminal.draw(|f| ui(f, &editor))?;
|
||||||
@@ -568,39 +496,31 @@ fn run_app<B: Backend>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui(f: &mut Frame, editor: &PatternValidationFormEditor<PatternValidationData>) {
|
fn ui(f: &mut Frame, editor: &AdvancedPatternFormEditor<AdvancedPatternData>) {
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([Constraint::Min(8), Constraint::Length(12)])
|
.constraints([Constraint::Min(8), Constraint::Length(15)])
|
||||||
.split(f.area());
|
.split(f.area());
|
||||||
|
|
||||||
render_enhanced_canvas(f, chunks[0], editor);
|
render_canvas_default(f, chunks[0], &editor.editor);
|
||||||
render_validation_status(f, chunks[1], editor);
|
render_advanced_validation_status(f, chunks[1], editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_enhanced_canvas(
|
fn render_advanced_validation_status(
|
||||||
f: &mut Frame,
|
f: &mut Frame,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
editor: &PatternValidationFormEditor<PatternValidationData>,
|
editor: &AdvancedPatternFormEditor<AdvancedPatternData>,
|
||||||
) {
|
|
||||||
render_canvas_default(f, area, &editor.editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_validation_status(
|
|
||||||
f: &mut Frame,
|
|
||||||
area: Rect,
|
|
||||||
editor: &PatternValidationFormEditor<PatternValidationData>,
|
|
||||||
) {
|
) {
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([
|
.constraints([
|
||||||
Constraint::Length(3), // Status bar
|
Constraint::Length(3), // Status bar
|
||||||
Constraint::Length(4), // Validation summary
|
Constraint::Length(5), // Validation summary
|
||||||
Constraint::Length(5), // Help
|
Constraint::Length(7), // Help
|
||||||
])
|
])
|
||||||
.split(area);
|
.split(area);
|
||||||
|
|
||||||
// Status bar with validation information
|
// Status bar
|
||||||
let mode_text = match editor.mode() {
|
let mode_text = match editor.mode() {
|
||||||
AppMode::Edit => "INSERT",
|
AppMode::Edit => "INSERT",
|
||||||
AppMode::ReadOnly => "NORMAL",
|
AppMode::ReadOnly => "NORMAL",
|
||||||
@@ -608,42 +528,43 @@ 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 = format!("-- {} -- {} | Advanced Patterns: {}", mode_text, editor.debug_message(), validation_status);
|
||||||
format!("-- {} -- {} [{}] | Pattern Validation: {}",
|
|
||||||
mode_text, editor.debug_message(), editor.get_command_buffer(), validation_status)
|
|
||||||
} else {
|
|
||||||
format!("-- {} -- {} | Pattern Validation: {}",
|
|
||||||
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("🔍 Pattern Validation Status"));
|
.block(Block::default().borders(Borders::ALL).title("🚀 Advanced Pattern Validation"));
|
||||||
|
|
||||||
f.render_widget(status, chunks[0]);
|
f.render_widget(status, chunks[0]);
|
||||||
|
|
||||||
// Validation summary with field switching info
|
// Enhanced validation summary
|
||||||
let summary = editor.editor.validation_summary();
|
let summary = editor.editor.validation_summary();
|
||||||
let summary_text = if editor.validation_enabled {
|
let field_info = match editor.current_field() {
|
||||||
let switch_info = if editor.field_switch_blocked {
|
0 => "Time format (HH:MM) - Tests exact chars + numeric ranges",
|
||||||
format!("\n🚫 Field switching blocked: {}",
|
1 => "Hex color (#RRGGBB) - Tests OneOf filter with case insensitive",
|
||||||
editor.block_reason.as_deref().unwrap_or("Unknown reason"))
|
2 => "IPv4 address - Tests complex dot positioning",
|
||||||
} else {
|
3 => "Product code (ABC-123-XYZ) - Tests section-based patterns",
|
||||||
"\n✅ Field switching allowed".to_string()
|
4 => "Date code (2024W15) - Tests From position filtering",
|
||||||
|
5 => "Binary input - Tests limited character set (0,1 only)",
|
||||||
|
6 => "Complex ID - Tests overlapping/conflicting rules",
|
||||||
|
7 => "Custom pattern - Tests advanced custom validation logic",
|
||||||
|
_ => "Unknown field",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let summary_text = if editor.validation_enabled {
|
||||||
format!(
|
format!(
|
||||||
"📊 Pattern Validation Summary: {} fields configured, {} validated{}\n\
|
"📊 Advanced Pattern Summary: {} fields with complex rules\n\
|
||||||
✅ Valid: {} ⚠️ Warnings: {} ❌ Errors: {} 📈 Progress: {:.0}%",
|
Current Field: {}\n\
|
||||||
|
✅ Valid: {} ⚠️ Warnings: {} ❌ Errors: {} 📈 Progress: {:.0}%\n\
|
||||||
|
🎯 Pattern Focus: {}",
|
||||||
summary.total_fields,
|
summary.total_fields,
|
||||||
summary.validated_fields,
|
editor.current_field() + 1,
|
||||||
switch_info,
|
|
||||||
summary.valid_fields,
|
summary.valid_fields,
|
||||||
summary.warning_fields,
|
summary.warning_fields,
|
||||||
summary.error_fields,
|
summary.error_fields,
|
||||||
summary.completion_percentage() * 100.0
|
summary.completion_percentage() * 100.0,
|
||||||
|
field_info
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
"❌ Pattern validation is currently DISABLED\nPress F1 to enable validation".to_string()
|
"❌ Advanced pattern validation is DISABLED\nPress F1 to enable and see the magic!".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let summary_style = if summary.has_errors() {
|
let summary_style = if summary.has_errors() {
|
||||||
@@ -655,32 +576,33 @@ fn render_validation_status(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let validation_summary = Paragraph::new(summary_text)
|
let validation_summary = Paragraph::new(summary_text)
|
||||||
.block(Block::default().borders(Borders::ALL).title("📈 Pattern Validation Overview"))
|
.block(Block::default().borders(Borders::ALL).title("🎯 Advanced Pattern Analysis"))
|
||||||
.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]);
|
||||||
|
|
||||||
// Pattern-specific help text
|
// Enhanced help text
|
||||||
let help_text = match editor.mode() {
|
let help_text = match editor.mode() {
|
||||||
AppMode::ReadOnly => {
|
AppMode::ReadOnly => {
|
||||||
"🔍 PATTERN VALIDATION DEMO: Each field has specific character patterns!\n\
|
"🚀 ADVANCED PATTERN SHOWCASE - Each field demonstrates different edge cases!\n\
|
||||||
License Plate: 2 letters + 3 numbers (AB123)\n\
|
🕐 Time: Numeric+exact chars 🎨 Hex: OneOf with case-insensitive 🌐 IPv4: Complex positioning\n\
|
||||||
Phone: Numbers with dashes at positions 3 and 7 (123-456-7890)\n\
|
🏷️ Product: Multi-section rules 📅 Date: From-position filtering 🔢 Binary: Limited charset\n\
|
||||||
Credit Card: Number groups separated by dashes (1234-5678-9012-3456)\n\
|
🎯 Complex: Overlapping rules 🚀 Custom: Advanced logic functions\n\
|
||||||
Custom ID: 2 letters + alphanumeric (AB123def)\n\
|
\n\
|
||||||
Movement: hjkl/arrows=move, Tab/Shift+Tab=fields, i/a=insert, F1=toggle validation"
|
Movement: hjkl/arrows=move, Tab/Shift+Tab=fields, i/a=insert, F1=toggle, ?=info"
|
||||||
}
|
}
|
||||||
AppMode::Edit => {
|
AppMode::Edit => {
|
||||||
"✏️ INSERT MODE - Type to test pattern validation!\n\
|
"✏️ INSERT MODE - Testing advanced pattern validation!\n\
|
||||||
Pattern validation will reject characters that don't match the expected pattern\n\
|
Each character is validated against complex rules in real-time\n\
|
||||||
|
Try entering invalid characters to see detailed error messages\n\
|
||||||
arrows=move, Backspace/Del=delete, Esc=normal, Tab=next field"
|
arrows=move, Backspace/Del=delete, Esc=normal, Tab=next field"
|
||||||
}
|
}
|
||||||
_ => "🔍 Pattern Validation Demo Active!"
|
_ => "🚀 Advanced Pattern Validation Active!"
|
||||||
};
|
};
|
||||||
|
|
||||||
let help = Paragraph::new(help_text)
|
let help = Paragraph::new(help_text)
|
||||||
.block(Block::default().borders(Borders::ALL).title("🚀 Pattern Validation Commands"))
|
.block(Block::default().borders(Borders::ALL).title("🎯 Advanced Pattern Commands & Info"))
|
||||||
.style(Style::default().fg(Color::Gray))
|
.style(Style::default().fg(Color::Gray))
|
||||||
.wrap(Wrap { trim: true });
|
.wrap(Wrap { trim: true });
|
||||||
|
|
||||||
@@ -688,12 +610,12 @@ fn render_validation_status(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// Print feature status
|
println!("🚀 Canvas Advanced Pattern Validation Demo");
|
||||||
println!("🔍 Canvas Pattern Validation TUI Demo");
|
|
||||||
println!("✅ validation feature: ENABLED");
|
println!("✅ validation feature: ENABLED");
|
||||||
println!("✅ gui feature: ENABLED");
|
println!("✅ gui feature: ENABLED");
|
||||||
println!("🚀 Pattern-based validation: ACTIVE");
|
println!("🎯 Advanced pattern filtering: ACTIVE");
|
||||||
println!("📊 Try typing in fields with different patterns!");
|
println!("🧪 Edge cases and complex patterns: READY");
|
||||||
|
println!("💡 Each field showcases different validation capabilities!");
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
enable_raw_mode()?;
|
enable_raw_mode()?;
|
||||||
@@ -702,8 +624,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let backend = CrosstermBackend::new(stdout);
|
let backend = CrosstermBackend::new(stdout);
|
||||||
let mut terminal = Terminal::new(backend)?;
|
let mut terminal = Terminal::new(backend)?;
|
||||||
|
|
||||||
let data = PatternValidationData::new();
|
let data = AdvancedPatternData::new();
|
||||||
let editor = PatternValidationFormEditor::new(data);
|
let editor = AdvancedPatternFormEditor::new(data);
|
||||||
|
|
||||||
let res = run_app(&mut terminal, editor);
|
let res = run_app(&mut terminal, editor);
|
||||||
|
|
||||||
@@ -719,6 +641,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
println!("{:?}", err);
|
println!("{:?}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("🔍 Pattern validation demo completed!");
|
println!("🚀 Advanced pattern validation demo completed!");
|
||||||
|
println!("🎯 Hope you enjoyed seeing all the edge cases in action!");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user