Enhance TUI: add paste event handling, integrate bracketed paste mode, and implement paste support in editing mode.

Fixes #20
This commit is contained in:
2025-09-30 02:27:09 +02:00
parent 63ca71c6ae
commit a5727c0a1d
3 changed files with 27 additions and 3 deletions

View File

@@ -11,7 +11,7 @@ use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use crossterm::{ use crossterm::{
event::{DisableMouseCapture, EnableMouseCapture}, event::{DisableMouseCapture, EnableMouseCapture, DisableBracketedPaste, EnableBracketedPaste},
execute, execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
}; };
@@ -57,7 +57,7 @@ async fn main() -> Result<()> {
// Terminal setup // Terminal setup
enable_raw_mode()?; enable_raw_mode()?;
let mut stdout = io::stdout(); let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; execute!(stdout, EnterAlternateScreen, EnableMouseCapture, EnableBracketedPaste)?;
let backend = CrosstermBackend::new(stdout); let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?; let mut terminal = Terminal::new(backend)?;
@@ -74,7 +74,8 @@ async fn main() -> Result<()> {
execute!( execute!(
terminal.backend_mut(), terminal.backend_mut(),
LeaveAlternateScreen, LeaveAlternateScreen,
DisableMouseCapture DisableMouseCapture,
DisableBracketedPaste
)?; )?;
terminal.show_cursor()?; terminal.show_cursor()?;

View File

@@ -381,6 +381,24 @@ impl ChatApp {
Event::Tick => { Event::Tick => {
// Future: update streaming timers // Future: update streaming timers
} }
Event::Paste(text) => {
// Handle paste events - insert text directly without triggering sends
if matches!(self.mode, InputMode::Editing) {
// In editing mode, insert the pasted text directly into textarea
let lines: Vec<&str> = text.lines().collect();
for (i, line) in lines.iter().enumerate() {
for ch in line.chars() {
self.textarea.insert_char(ch);
}
// Insert newline between lines (but not after the last line)
if i < lines.len() - 1 {
self.textarea.insert_newline();
}
}
self.sync_textarea_to_buffer();
}
// Ignore paste events in other modes
}
Event::Key(key) => match self.mode { Event::Key(key) => match self.mode {
InputMode::Normal => { InputMode::Normal => {
// Handle multi-key sequences first // Handle multi-key sequences first

View File

@@ -11,6 +11,8 @@ pub enum Event {
/// Terminal resize event /// Terminal resize event
#[allow(dead_code)] #[allow(dead_code)]
Resize(u16, u16), Resize(u16, u16),
/// Paste event
Paste(String),
/// Tick event for regular updates /// Tick event for regular updates
Tick, Tick,
} }
@@ -60,6 +62,9 @@ impl EventHandler {
crossterm::event::Event::Resize(width, height) => { crossterm::event::Event::Resize(width, height) => {
let _ = self.sender.send(Event::Resize(width, height)); let _ = self.sender.send(Event::Resize(width, height));
} }
crossterm::event::Event::Paste(text) => {
let _ = self.sender.send(Event::Paste(text));
}
_ => {} _ => {}
} }
} }