suggestions2 only on tab trigger and not automatic

This commit is contained in:
Priec
2025-08-11 23:05:56 +02:00
parent 082093ea17
commit 189d3d2fc5

View File

@@ -1,8 +1,8 @@
// examples/suggestions2.rs // examples/suggestions2.rs
//! Production-ready non-blocking suggestions demonstration //! Production-ready Tab-triggered suggestions demonstration
//! //!
//! This example demonstrates: //! This example demonstrates:
//! - Instant, responsive suggestions dropdown //! - Tab-triggered suggestions dropdown
//! - Non-blocking architecture for real network/database calls //! - Non-blocking architecture for real network/database calls
//! - Multiple suggestion field types //! - Multiple suggestion field types
//! - Professional-grade user experience //! - Professional-grade user experience
@@ -62,7 +62,7 @@ impl<D: DataProvider> AutoCursorFormEditor<D> {
Self { Self {
editor: FormEditor::new(data_provider), editor: FormEditor::new(data_provider),
has_unsaved_changes: false, has_unsaved_changes: false,
debug_message: "🚀 Production-Ready Suggestions Demo - Copy this architecture for your app!".to_string(), debug_message: "🚀 Production-Ready Tab-Triggered Suggestions Demo - Copy this architecture for your app!".to_string(),
command_buffer: String::new(), command_buffer: String::new(),
} }
} }
@@ -232,12 +232,12 @@ impl<D: DataProvider> AutoCursorFormEditor<D> {
fn enter_edit_mode(&mut self) { fn enter_edit_mode(&mut self) {
self.editor.enter_edit_mode(); // 🎯 Library automatically sets cursor to bar | self.editor.enter_edit_mode(); // 🎯 Library automatically sets cursor to bar |
self.debug_message = "✏️ INSERT MODE - Cursor: Steady Bar |".to_string(); self.debug_message = "✏️ INSERT MODE - Cursor: Steady Bar | - Press Tab for suggestions".to_string();
} }
fn enter_append_mode(&mut self) { fn enter_append_mode(&mut self) {
self.editor.enter_append_mode(); // 🎯 Library automatically positions cursor and sets mode self.editor.enter_append_mode(); // 🎯 Library automatically positions cursor and sets mode
self.debug_message = "✏️ INSERT (append) - Cursor: Steady Bar |".to_string(); self.debug_message = "✏️ INSERT (append) - Cursor: Steady Bar | - Press Tab for suggestions".to_string();
} }
fn exit_edit_mode(&mut self) { fn exit_edit_mode(&mut self) {
@@ -289,17 +289,6 @@ impl<D: DataProvider> AutoCursorFormEditor<D> {
} }
} }
/// Auto-trigger suggestions for current field (production pattern)
///
/// Call this after character input, deletion, or field entry to automatically
/// show suggestions. Perfect for real-time search-as-you-type functionality.
async fn auto_trigger_suggestions(&mut self, provider: &mut ProductionSuggestionsProvider) {
let field_index = self.current_field();
if self.data_provider().supports_suggestions(field_index) {
self.trigger_suggestions_async(provider, field_index).await;
}
}
fn suggestions_next(&mut self) { fn suggestions_next(&mut self) {
self.editor.suggestions_next(); self.editor.suggestions_next();
} }
@@ -607,7 +596,7 @@ impl SuggestionsProvider for ProductionSuggestionsProvider {
} }
} }
/// Production-ready key handling with non-blocking suggestions /// Production-ready key handling with Tab-triggered suggestions
async fn handle_key_press( async fn handle_key_press(
key: KeyCode, key: KeyCode,
modifiers: KeyModifiers, modifiers: KeyModifiers,
@@ -625,7 +614,7 @@ async fn handle_key_press(
} }
match (mode, key, modifiers) { match (mode, key, modifiers) {
// === NON-BLOCKING SUGGESTIONS HANDLING === // === TAB-TRIGGERED SUGGESTIONS HANDLING ===
(_, KeyCode::Tab, _) => { (_, KeyCode::Tab, _) => {
if editor.is_suggestions_active() { if editor.is_suggestions_active() {
// Cycle through suggestions // Cycle through suggestions
@@ -677,22 +666,20 @@ async fn handle_key_press(
} }
} }
// === MODE TRANSITIONS WITH AUTO-SUGGESTIONS === // === MODE TRANSITIONS (NO AUTO-SUGGESTIONS) ===
(AppMode::ReadOnly, KeyCode::Char('i'), _) => { (AppMode::ReadOnly, KeyCode::Char('i'), _) => {
editor.enter_edit_mode(); editor.enter_edit_mode();
editor.clear_command_buffer(); editor.clear_command_buffer();
// Auto-show suggestions on entering insert mode
editor.auto_trigger_suggestions(suggestions_provider).await;
} }
(AppMode::ReadOnly, KeyCode::Char('a'), _) => { (AppMode::ReadOnly, KeyCode::Char('a'), _) => {
editor.enter_append_mode(); editor.enter_append_mode();
editor.set_debug_message("✏️ INSERT (append) - Cursor: Steady Bar |".to_string()); editor.set_debug_message("✏️ INSERT (append) - Cursor: Steady Bar | - Press Tab for suggestions".to_string());
editor.clear_command_buffer(); editor.clear_command_buffer();
} }
(AppMode::ReadOnly, KeyCode::Char('A'), _) => { (AppMode::ReadOnly, KeyCode::Char('A'), _) => {
editor.move_line_end(); editor.move_line_end();
editor.enter_edit_mode(); editor.enter_edit_mode();
editor.set_debug_message("✏️ INSERT (end of line) - Cursor: Steady Bar |".to_string()); editor.set_debug_message("✏️ INSERT (end of line) - Cursor: Steady Bar | - Press Tab for suggestions".to_string());
editor.clear_command_buffer(); editor.clear_command_buffer();
} }
@@ -821,16 +808,22 @@ async fn handle_key_press(
editor.move_line_end(); editor.move_line_end();
} }
// === DELETE OPERATIONS WITH AUTO-SUGGESTIONS === // === DELETE OPERATIONS (AUTO-FETCH WHEN SUGGESTIONS ACTIVE) ===
(AppMode::Edit, KeyCode::Backspace, _) => { (AppMode::Edit, KeyCode::Backspace, _) => {
editor.delete_backward()?; editor.delete_backward()?;
// Auto-trigger suggestions after deletion // Auto-fetch only if suggestions are already active (triggered by Tab)
editor.auto_trigger_suggestions(suggestions_provider).await; if editor.is_suggestions_active() {
let field_index = editor.current_field();
editor.trigger_suggestions_async(suggestions_provider, field_index).await;
}
} }
(AppMode::Edit, KeyCode::Delete, _) => { (AppMode::Edit, KeyCode::Delete, _) => {
editor.delete_forward()?; editor.delete_forward()?;
// Auto-trigger suggestions after deletion // Auto-fetch only if suggestions are already active (triggered by Tab)
editor.auto_trigger_suggestions(suggestions_provider).await; if editor.is_suggestions_active() {
let field_index = editor.current_field();
editor.trigger_suggestions_async(suggestions_provider, field_index).await;
}
} }
// Delete operations in normal mode (vim x) // Delete operations in normal mode (vim x)
@@ -843,11 +836,14 @@ async fn handle_key_press(
editor.set_debug_message("X: deleted character backward".to_string()); editor.set_debug_message("X: deleted character backward".to_string());
} }
// === CHARACTER INPUT WITH REAL-TIME SUGGESTIONS === // === CHARACTER INPUT (AUTO-FETCH WHEN SUGGESTIONS ACTIVE) ===
(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)?;
// Auto-trigger suggestions after typing - this is the magic! // Auto-fetch only if suggestions are already active (triggered by Tab)
editor.auto_trigger_suggestions(suggestions_provider).await; if editor.is_suggestions_active() {
let field_index = editor.current_field();
editor.trigger_suggestions_async(suggestions_provider, field_index).await;
}
} }
// === DEBUG/INFO COMMANDS === // === DEBUG/INFO COMMANDS ===
@@ -980,7 +976,7 @@ fn render_status_and_help(
); );
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("🚀 Production-Ready Non-Blocking Suggestions")); .block(Block::default().borders(Borders::ALL).title("🚀 Production-Ready Smart Suggestions (Tab to activate → type to filter)"));
f.render_widget(status, chunks[0]); f.render_widget(status, chunks[0]);
@@ -992,19 +988,19 @@ fn render_status_and_help(
Actions: i/a/A=insert, v/V=visual, x/X=delete, ?=info, Enter=next field\n\ Actions: i/a/A=insert, v/V=visual, x/X=delete, ?=info, Enter=next field\n\
Integration: Replace data sources with your APIs, databases, caches\n\ Integration: Replace data sources with your APIs, databases, caches\n\
Architecture: Non-blocking • Instant UI • Stale protection • Professional UX\n\ Architecture: Non-blocking • Instant UI • Stale protection • Professional UX\n\
Tab=suggestions, Enter=select • Ready for: REST, GraphQL, SQL, Redis, etc." 🔑 Tab=activate suggestions → type to filter • Enter=select • Ready for: REST, GraphQL, SQL, Redis"
} }
AppMode::Edit => { AppMode::Edit => {
"🚀 INSERT MODE - Type for instant suggestions!\n\ "🚀 INSERT MODE - Press Tab to activate suggestions, then type to filter!\n\
Real-time search-as-you-type with non-blocking architecture\n\ Tab=activate suggestions • Type/Backspace=filter while active • Enter=select\n\
Perfect for: User search, autocomplete, typeahead, smart suggestions\n\ Perfect for: Autocomplete, search dropdowns, data entry assistance\n\
Navigation: arrows=move, Ctrl+arrows=words, Home/End=line edges\n\ Navigation: arrows=move, Ctrl+arrows=words, Home/End=line edges\n\
Copy this pattern for production: API calls, database queries, cache lookups" Copy this pattern for production: API calls, database queries, cache lookups"
} }
AppMode::Highlight => { AppMode::Highlight => {
"🚀 VISUAL MODE - Selection with suggestions support\n\ "🚀 VISUAL MODE - Selection with suggestions support\n\
Selection: hjkl/arrows=extend, w/b/e=word selection, Esc=normal\n\ Selection: hjkl/arrows=extend, w/b/e=word selection, Esc=normal\n\
Professional editor experience with modern autocomplete!" Professional editor experience with Tab-triggered autocomplete!"
} }
_ => "🚀 Copy this suggestions architecture for your production app!" _ => "🚀 Copy this suggestions architecture for your production app!"
}; };
@@ -1019,8 +1015,8 @@ fn render_status_and_help(
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Print production-ready information // Print production-ready information
println!("🚀 Production-Ready Non-Blocking Suggestions Demo"); println!("🚀 Production-Ready Tab-Triggered Suggestions Demo");
println!("Instant, responsive UI - no blocking on network/database calls"); println!("Press Tab to activate suggestions, then type to filter in real-time");
println!("✅ Professional autocomplete architecture"); println!("✅ Professional autocomplete architecture");
println!("✅ Copy this pattern for your production application!"); println!("✅ Copy this pattern for your production application!");
println!(); println!();
@@ -1033,9 +1029,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" 🔗 gRPC Services"); println!(" 🔗 gRPC Services");
println!(); println!();
println!("⚡ Key Features:"); println!("⚡ Key Features:");
println!("Dropdown appears instantly (never waits for network)"); println!("Press Tab to activate suggestions dropdown");
println!(" • Real-time filtering while suggestions are active");
println!(" • Built-in stale result protection"); println!(" • Built-in stale result protection");
println!("Search-as-you-type with real-time filtering"); println!("Tab cycles through suggestions");
println!(" • Professional-grade user experience"); println!(" • Professional-grade user experience");
println!(" • Easy to integrate with any async data source"); println!(" • Easy to integrate with any async data source");
println!(); println!();