fix(tui): clear composer and block paste-burst under model picker

Opening the model picker clears the composer buffer and rejects paste
bursts while a modal owns keys so typed/pasted text does not leak in.
This commit is contained in:
CodeWhale Bot committed 2026-09-04 05:47:06 +00:00
1 parent e8b8522b2c
commit 9b2eeca894
3 files changed
+34

No files matched your search

+5
View File
@@ -1862,6 +1862,11 @@ pub(crate) async fn apply_command_result(
}
AppAction::OpenModelPicker => {
if app.view_stack.top_kind() != Some(ModalKind::ModelPicker) {
// Slash `/model` and the picker share one grammar: the
// composer must not keep a leftover `/model` buffer
// (or a held paste-burst) under the picker query.
app.clear_input();
app.paste_burst.clear_after_explicit_paste();
app.view_stack
.push(crate::tui::model_picker::ModelPickerView::new(app, config));
}
+6
View File
@@ -152,6 +152,12 @@ fn handle_focused_transcript_action_char(app: &mut App, ch: char) -> bool {
/// transcript action only when the composer is still empty and the last
/// rendered owner accepts it; otherwise it remains ordinary input.
pub(super) fn flush_paste_burst_before_composer(app: &mut App, now: Instant) -> bool {
if !app.view_stack.is_empty() {
// One grammar buffer: a modal owns keys. Held burst must not leak
// into the composer (leaky `/model` after the picker opens).
app.paste_burst.clear_after_explicit_paste();
return false;
}
match app.take_paste_burst_flush_if_enabled(now) {
crate::tui::paste_burst::FlushResult::Paste(text) => {
app.insert_str(&text);
+23
View File
@@ -4912,6 +4912,29 @@ fn raw_paste_beginning_with_space_preserves_payload_over_reasoning_action() {
assert_eq!(app.input, " x");
}
#[test]
fn paste_burst_does_not_leak_into_composer_while_a_modal_owns_keys() {
// `/model` opens a picker with its own query. A held paste-burst from
// typing the slash command must not flush into the composer under it.
let mut app = Box::new(create_test_app());
app.use_paste_burst_detection = true;
app.bracketed_paste_seen = false;
let now = Instant::now();
let slash = KeyEvent::new(KeyCode::Char('/'), KeyModifiers::NONE);
assert!(handle_plain_key_before_composer(&mut app, &slash, now));
app.view_stack.push(HelpView::new());
let flushed = flush_paste_burst_before_composer(
&mut app,
now + crate::tui::paste_burst::PasteBurst::recommended_flush_delay(),
);
assert!(!flushed, "modal-owned keys must not flush into the composer");
assert!(
app.input.is_empty() || app.input == "/",
"composer must not gain leaked burst text under a modal: {:?}",
app.input
);
}
#[test]
fn active_raw_paste_keeps_space_as_payload_over_reasoning_action() {
let mut app = create_test_app();