PicoBot/src/client/tui/event.rs

121 lines
3.6 KiB
Rust

use crate::client::tui::app::{App, MessageRole};
use crate::protocol::serialize_inbound;
use crate::protocol::WsInbound;
use crossterm::event::{KeyCode, KeyEvent};
use futures_util::SinkExt;
pub async fn handle_key_event(app: &mut App, key: KeyEvent) {
if app.show_help {
match key.code {
KeyCode::Esc | KeyCode::Char('q') => {
app.toggle_help();
}
_ => {}
}
return;
}
if app.show_command_menu {
match key.code {
KeyCode::Esc => {
app.show_command_menu = false;
app.selected_command_idx = 0;
}
KeyCode::Up => {
app.select_prev_command();
}
KeyCode::Down => {
app.select_next_command();
}
KeyCode::Enter => {
app.insert_command();
app.show_command_menu = false;
app.selected_command_idx = 0;
}
KeyCode::Tab => {
app.insert_command();
}
_ => {
// Handle normal input and check if menu should stay open
handle_normal_input(app, key).await;
}
}
return;
}
handle_normal_input(app, key).await;
}
async fn handle_normal_input(app: &mut App, key: KeyEvent) {
match key.code {
KeyCode::Esc | KeyCode::Char('q') => {
app.quit();
}
KeyCode::Char('?') => {
app.toggle_help();
}
KeyCode::Char(c) => {
app.input_insert_char(c);
// Show command menu when input starts with /
if !app.show_command_menu && (app.input == "/" || (app.input.len() > 1 && app.input.starts_with('/'))) {
app.show_command_menu = true;
app.selected_command_idx = 0;
} else if app.show_command_menu && !app.input.starts_with('/') {
app.show_command_menu = false;
}
}
KeyCode::Backspace => {
app.input_delete_char();
// Hide menu if input no longer starts with /
if app.show_command_menu && !app.input.starts_with('/') {
app.show_command_menu = false;
app.selected_command_idx = 0;
}
}
KeyCode::Left => {
app.input_move_cursor_left();
}
KeyCode::Right => {
app.input_move_cursor_right();
}
KeyCode::Home => {
app.input_move_cursor_to_start();
}
KeyCode::End => {
app.input_move_cursor_to_end();
}
KeyCode::Up => {
app.scroll_chat_up();
}
KeyCode::Down => {
app.scroll_chat_down();
}
KeyCode::Enter => {
let input = app.take_input();
app.show_command_menu = false;
app.selected_command_idx = 0;
if !input.is_empty() {
process_input(app, input).await;
}
}
_ => {}
}
}
async fn process_input(app: &mut App, input: String) {
app.add_message(MessageRole::User, input.clone());
if let Some(sender) = &mut app.ws_sender {
let inbound = WsInbound::UserInput {
content: input,
chat_id: app.current_session_id.clone(),
channel: None,
sender_id: None,
};
if let Ok(text) = serialize_inbound(&inbound) {
let _ = sender.send(tokio_tungstenite::tungstenite::Message::Text(text.into())).await;
}
}
}