diff --git a/crates/tui/src/tui/provider_picker.rs b/crates/tui/src/tui/provider_picker.rs index 00dc14e2..c43a41f1 100644 --- a/crates/tui/src/tui/provider_picker.rs +++ b/crates/tui/src/tui/provider_picker.rs @@ -246,6 +246,16 @@ impl ModalView for ProviderPickerView { self } + fn handle_paste(&mut self, text: &str) -> ViewAction { + if self.stage == Stage::KeyEntry { + let sanitized: String = text.chars().filter(|c| !c.is_whitespace()).collect(); + if !sanitized.is_empty() { + self.api_key_input.push_str(&sanitized); + } + } + ViewAction::None + } + fn handle_key(&mut self, key: KeyEvent) -> ViewAction { match self.stage { Stage::List => match key.code { diff --git a/crates/tui/src/tui/ui.rs b/crates/tui/src/tui/ui.rs index 74e03596..53258cb6 100644 --- a/crates/tui/src/tui/ui.rs +++ b/crates/tui/src/tui/ui.rs @@ -1240,6 +1240,10 @@ async fn run_event_loop( sync_api_key_validation_status(app, false); } else if app.is_history_search_active() { app.history_search_insert_str(text); + } else if app.view_stack.handle_paste(text) { + // Modal consumed the paste (e.g. provider picker key entry) + } else if !app.view_stack.is_empty() { + // A non-consumed modal is open — don't leak paste into composer } else { // Paste into main input app.insert_paste_text(text); diff --git a/crates/tui/src/tui/views/mod.rs b/crates/tui/src/tui/views/mod.rs index b3ed31c1..4b700ea7 100644 --- a/crates/tui/src/tui/views/mod.rs +++ b/crates/tui/src/tui/views/mod.rs @@ -173,6 +173,9 @@ pub enum ViewAction { pub trait ModalView: std::any::Any { fn kind(&self) -> ModalKind; fn handle_key(&mut self, key: KeyEvent) -> ViewAction; + fn handle_paste(&mut self, _text: &str) -> ViewAction { + ViewAction::None + } fn handle_mouse(&mut self, _mouse: MouseEvent) -> ViewAction { ViewAction::None } @@ -245,6 +248,13 @@ impl ViewStack { self.apply_action(action) } + pub fn handle_paste(&mut self, text: &str) -> bool { + self.views + .last_mut() + .map(|view| matches!(view.handle_paste(text), ViewAction::None)) + .unwrap_or(false) + } + pub fn handle_mouse(&mut self, mouse: MouseEvent) -> Vec { let action = self .views