From cb376e8d5f3ae6420f759917eb7e29649d602593 Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 13 Jul 2026 22:17:21 +0000 Subject: [PATCH] Block help shortcut in queued prompt editor Co-Authored-By: Oz --- app/src/terminal/input.rs | 1 + app/src/terminal/view/queued_prompts_panel.rs | 4 ++ app/src/terminal/view/queued_prompts_tests.rs | 65 +++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/app/src/terminal/input.rs b/app/src/terminal/input.rs index 674e7591d95..89142f49211 100644 --- a/app/src/terminal/input.rs +++ b/app/src/terminal/input.rs @@ -2075,6 +2075,7 @@ pub fn init(app: &mut AppContext) { & id!(flags::EMPTY_INPUT_BUFFER) & id!(flags::ACTIVE_AGENT_VIEW) & !id!("LongRunningCommand") + & !id!(QUEUED_PROMPT_INLINE_EDITOR_OPEN_CONTEXT) & !(id!(flags::TERMINAL_MODE_INPUT) & id!(flags::LOCKED_INPUT)), )]); } diff --git a/app/src/terminal/view/queued_prompts_panel.rs b/app/src/terminal/view/queued_prompts_panel.rs index a3bdd489ca9..2f120f0dcc8 100644 --- a/app/src/terminal/view/queued_prompts_panel.rs +++ b/app/src/terminal/view/queued_prompts_panel.rs @@ -677,6 +677,10 @@ impl QueuedPromptsPanelView { #[cfg(test)] impl QueuedPromptsPanelView { + /// Test accessor for dispatching keystrokes directly to the inline edit editor. + pub(super) fn edit_editor_for_test(&self) -> ViewHandle { + self.edit_editor.clone() + } /// Test accessor: whether the "send now" button for `query_id` is currently disabled. pub(super) fn send_now_button_disabled_for_test( &self, diff --git a/app/src/terminal/view/queued_prompts_tests.rs b/app/src/terminal/view/queued_prompts_tests.rs index 024f0f535a6..26bdaccde8f 100644 --- a/app/src/terminal/view/queued_prompts_tests.rs +++ b/app/src/terminal/view/queued_prompts_tests.rs @@ -9,6 +9,7 @@ use std::rc::Rc; use std::str::FromStr; use warp_cli::agent::Harness; +use warpui::keymap::Keystroke; use warpui::platform::WindowStyle; use warpui::{App, SingletonEntity, TypedActionView, ViewContext, ViewHandle}; @@ -28,6 +29,7 @@ use crate::ai::blocklist::{ }; use crate::features::FeatureFlag; use crate::server::server_api::ai::SpawnAgentRequest; +use crate::settings::import::model::ImportedConfigModel; use crate::terminal::input::{Event as InputEvent, Input}; use crate::terminal::shared_session::SharedSessionStatus; use crate::terminal::view::ambient_agent::AmbientAgentViewModelEvent; @@ -1495,6 +1497,69 @@ fn redetermine_terminal_focus_preserves_focused_queued_prompt_editor() { }); } +#[test] +fn question_mark_is_inserted_while_editing_queued_prompt() { + App::test((), |mut app| async move { + let _agent_view_flag = FeatureFlag::AgentView.override_enabled(true); + let _queue_flag = FeatureFlag::QueueSlashCommand.override_enabled(true); + initialize_app_for_terminal_view(&mut app); + app.add_singleton_model(ImportedConfigModel::new); + app.update(|ctx| { + crate::terminal::input::init(ctx); + crate::editor::init(ctx); + }); + + let terminal = add_window_with_terminal(&mut app, None); + let terminal_view_id = terminal.read(&app, |view, _| view.view_id); + let conversation_id = + BlocklistAIHistoryModel::handle(&app).update(&mut app, |history, ctx| { + let id = history.start_new_conversation(terminal_view_id, false, false, false, ctx); + history.set_active_conversation_id(id, terminal_view_id, ctx); + id + }); + terminal.update(&mut app, |view, ctx| { + view.enter_agent_view_for_conversation( + None, + AgentViewEntryOrigin::ConversationSelector, + conversation_id, + ctx, + ); + }); + + let input = terminal.read(&app, |view, _| view.input.clone()); + let panel = input + .read(&app, |input, _| input.queued_prompts_panel().cloned()) + .expect("queue flag should create a queued prompts panel"); + let row_id = QueuedQueryModel::handle(&app).update(&mut app, |model, ctx| { + model.append(conversation_id, user_query("edit me"), ctx) + }); + panel.update(&mut app, |panel, ctx| { + panel.handle_action(&QueuedPromptsPanelAction::StartEditingRow(row_id), ctx); + }); + + let edit_editor = panel.read(&app, |panel, _| panel.edit_editor_for_test()); + let window_id = app.read(|ctx| terminal.window_id(ctx)); + let handled = app + .dispatch_keystroke( + window_id, + &[terminal.id(), input.id(), panel.id(), edit_editor.id()], + &Keystroke::parse("shift-?").expect("question-mark keystroke should parse"), + false, + ) + .expect("keystroke dispatch should succeed"); + assert!( + !handled, + "the parent input should not handle the queued editor's question mark" + ); + edit_editor.update(&mut app, |editor, ctx| { + editor.user_insert("?", ctx); + }); + edit_editor.read(&app, |editor, ctx| { + assert_eq!(editor.buffer_text(ctx), "edit me?"); + }); + }); +} + #[test] fn can_send_prompt_gates_buttons_and_hint_while_nonempty_input_gates_only_the_hint() { // When the host reports prompts cannot be sent (read-only shared-session viewer), every