use crossterm::{
event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
terminal::{disable_raw_mode, enable_raw_mode},
};
use sql_cli::app_state_container::SelectionMode;
use sql_cli::buffer::AppMode;
use sql_cli::ui::input::actions::{Action, ActionContext};
use sql_cli::ui::key_handling::{ChordResult, KeyChordHandler, KeyMapper};
use std::io::{self, Write};
fn format_key(key: &KeyEvent) -> String {
let mut result = String::new();
if key.modifiers.contains(KeyModifiers::CONTROL) {
result.push_str("Ctrl+");
}
if key.modifiers.contains(KeyModifiers::ALT) {
result.push_str("Alt+");
}
if key.modifiers.contains(KeyModifiers::SHIFT) {
result.push_str("Shift+");
}
match key.code {
KeyCode::Char(c) => result.push(c),
KeyCode::F(n) => result.push_str(&format!("F{n}")),
KeyCode::Up => result.push('↑'),
KeyCode::Down => result.push('↓'),
KeyCode::Left => result.push('←'),
KeyCode::Right => result.push('→'),
KeyCode::PageUp => result.push_str("PgUp"),
KeyCode::PageDown => result.push_str("PgDn"),
KeyCode::Home => result.push_str("Home"),
KeyCode::End => result.push_str("End"),
KeyCode::Enter => result.push_str("Enter"),
KeyCode::Tab => result.push_str("Tab"),
KeyCode::Backspace => result.push_str("Bksp"),
KeyCode::Delete => result.push_str("Del"),
KeyCode::Esc => result.push_str("Esc"),
_ => result.push('?'),
}
result
}
fn format_action(action: &Action) -> String {
match action {
Action::Navigate(nav) => format!("Navigate({nav:?})"),
Action::ToggleSelectionMode => "ToggleSelectionMode".to_string(),
Action::Quit => "Quit".to_string(),
Action::ForceQuit => "ForceQuit".to_string(),
Action::ShowHelp => "ShowHelp".to_string(),
Action::ShowDebugInfo => "ShowDebugInfo".to_string(),
Action::ToggleColumnPin => "ToggleColumnPin".to_string(),
Action::Sort(col) => format!("Sort({col:?})"),
Action::ExitCurrentMode => "ExitCurrentMode".to_string(),
_ => format!("{action:?}"),
}
}
fn main() -> io::Result<()> {
println!("╔══════════════════════════════════════════════════════════════╗");
println!("║ SQL CLI Action System Logger (Simple Version) ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ Press keys to see how they map to actions. ║");
println!("║ Try: j, k, h, l, 5j, v, p, s, F1, arrows, etc. ║");
println!("║ Press Ctrl+C or 'q' to quit. ║");
println!("╚══════════════════════════════════════════════════════════════╝");
println!();
enable_raw_mode()?;
let mut key_mapper = KeyMapper::new();
let mut chord_handler = KeyChordHandler::new();
let mut count_display = String::new();
loop {
if event::poll(std::time::Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
if key.kind != crossterm::event::KeyEventKind::Press {
continue;
}
let key_str = format_key(&key);
if chord_handler.is_chord_mode_active() {
println!("│ {key_str:6} │ [Chord active, processing...]");
}
let chord_result = chord_handler.process_key(key);
match chord_result {
ChordResult::CompleteChord(action) => {
println!("│ {key_str:6} │ CHORD COMPLETE => {action:?}");
io::stdout().flush().unwrap();
if matches!(action, sql_cli::ui::input::actions::Action::Quit) {
break;
}
continue;
}
ChordResult::PartialChord(description) => {
println!("│ {key_str:6} │ CHORD: {description}");
io::stdout().flush().unwrap();
continue;
}
ChordResult::Cancelled => {
println!("│ {key_str:6} │ CHORD CANCELLED");
io::stdout().flush().unwrap();
continue;
}
ChordResult::SingleKey(_) => {
}
}
let context = ActionContext {
mode: AppMode::Results,
selection_mode: SelectionMode::Row,
has_results: true,
has_filter: false,
has_search: false,
row_count: 100,
column_count: 10,
current_row: 5,
current_column: 2,
};
let count_before = key_mapper.get_count_buffer().to_string();
let was_collecting = !count_before.is_empty();
let action = key_mapper.map_key(key, &context);
let count_after = key_mapper.get_count_buffer().to_string();
let is_collecting = !count_after.is_empty();
if was_collecting && !is_collecting && action.is_some() {
println!(
"│ {:6} │ Count: {:3} │ => {}",
key_str,
count_before,
format_action(action.as_ref().unwrap())
);
} else if is_collecting {
count_display = count_after.clone();
println!("│ {key_str:6} │ Building count: {count_display} │");
} else if let Some(ref act) = action {
println!("│ {:6} │ => {}", key_str, format_action(act));
} else {
println!("│ {key_str:6} │ (no mapping in Results mode)");
}
io::stdout().flush().unwrap();
if matches!(action, Some(Action::Quit | Action::ForceQuit)) {
break;
}
}
}
}
disable_raw_mode()?;
println!();
println!("Goodbye!");
Ok(())
}