diff --git a/app/src/terminal/input.rs b/app/src/terminal/input.rs index 674e7591d95..3d722b0b293 100644 --- a/app/src/terminal/input.rs +++ b/app/src/terminal/input.rs @@ -2074,6 +2074,7 @@ pub fn init(app: &mut AppContext) { & !id!("IMEOpen") & id!(flags::EMPTY_INPUT_BUFFER) & id!(flags::ACTIVE_AGENT_VIEW) + & !id!(QUEUED_PROMPT_INLINE_EDITOR_OPEN_CONTEXT) & !id!("LongRunningCommand") & !(id!(flags::TERMINAL_MODE_INPUT) & id!(flags::LOCKED_INPUT)), )]); diff --git a/app/src/terminal/input_tests.rs b/app/src/terminal/input_tests.rs index 3adf1cf92dd..6631dee5114 100644 --- a/app/src/terminal/input_tests.rs +++ b/app/src/terminal/input_tests.rs @@ -1448,6 +1448,113 @@ fn seed_active_conversation(app: &mut App, terminal_view_id: EntityId) -> AIConv id }) } +#[test] +fn question_mark_edits_queued_prompt_instead_of_opening_agent_help() { + 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(&mut app); + + let (window_id, terminal) = + add_window_with_bootstrapped_terminal_and_window_id(&mut app, None, None).await; + let (conversation_id, input, panel) = terminal.update(&mut app, |view, ctx| { + let conversation_id = view.agent_view_controller().update(ctx, |controller, ctx| { + controller + .try_enter_agent_view( + None, + AgentViewEntryOrigin::Input { + was_prompt_autodetected: false, + }, + ctx, + ) + .expect("should enter agent view") + }); + let input = view.input().clone(); + let panel = input + .as_ref(ctx) + .queued_prompts_panel() + .cloned() + .expect("queue flag should create a queued prompts panel"); + (conversation_id, input, panel) + }); + let query_id = QueuedQueryModel::handle(&app).update(&mut app, |model, ctx| { + model.append( + conversation_id, + QueuedQuery::new("Why".to_owned(), QueuedQueryOrigin::QueueSlashCommand), + ctx, + ) + }); + panel.update(&mut app, |panel, ctx| { + panel.handle_action( + &crate::terminal::view::queued_prompts_panel::QueuedPromptsPanelAction::StartEditingRow( + query_id, + ), + ctx, + ); + }); + + input.read(&app, |input, ctx| { + assert!(input.buffer_text(ctx).is_empty()); + assert!(!input + .agent_shortcut_view_model + .as_ref(ctx) + .is_shortcut_view_open()); + }); + panel.read(&app, |panel, ctx| { + assert!(panel.is_inline_edit_editor_focused(ctx)); + }); + + let edit_editor = panel.read(&app, |panel, _| panel.edit_editor_for_test()); + let question_mark = + Keystroke::parse("shift-?").expect("question mark keystroke should parse"); + let keydown_handled = app + .dispatch_keystroke( + window_id, + &[terminal.id(), input.id(), panel.id(), edit_editor.id()], + &question_mark, + false, + ) + .expect("question mark dispatch should succeed"); + assert!( + !keydown_handled, + "the Agent View help binding should defer to the queued prompt editor" + ); + input.read(&app, |input, ctx| { + assert!(!input + .agent_shortcut_view_model + .as_ref(ctx) + .is_shortcut_view_open()); + }); + panel.read(&app, |panel, ctx| { + assert!(panel.is_inline_edit_editor_focused(ctx)); + }); + // Once the keymap leaves the key unhandled, the platform's typed-character event + // reaches the focused editor and invokes this same insertion path. + edit_editor.update(&mut app, |editor, ctx| { + editor.user_insert("?", ctx); + }); + input.read(&app, |input, ctx| { + assert!( + input.buffer_text(ctx).is_empty(), + "typed characters should not reach the host input" + ); + }); + panel.read(&app, |panel, ctx| { + assert_eq!(panel.edit_buffer_text_for_test(ctx), "Why?"); + }); + input.read(&app, |input, ctx| { + assert!(!input + .agent_shortcut_view_model + .as_ref(ctx) + .is_shortcut_view_open()); + }); + + panel.update(&mut app, |panel, ctx| panel.commit_edit(ctx)); + QueuedQueryModel::handle(&app).read(&app, |model, _| { + assert_eq!(model.queue(conversation_id)[0].text(), "Why?"); + }); + }); +} /// Enter on an empty buffer sends the top queued prompt; a second Enter sends the next row. /// The buffer stays empty throughout. diff --git a/app/src/terminal/view/queued_prompts_panel.rs b/app/src/terminal/view/queued_prompts_panel.rs index a3bdd489ca9..885e2e766d6 100644 --- a/app/src/terminal/view/queued_prompts_panel.rs +++ b/app/src/terminal/view/queued_prompts_panel.rs @@ -703,6 +703,15 @@ impl QueuedPromptsPanelView { editor.set_buffer_text(text, ctx); }); } + + pub(crate) fn edit_buffer_text_for_test(&self, ctx: &AppContext) -> String { + self.edit_editor + .read(ctx, |editor, ctx| editor.buffer_text(ctx)) + } + + pub(crate) fn edit_editor_for_test(&self) -> ViewHandle { + self.edit_editor.clone() + } } impl TypedActionView for QueuedPromptsPanelView {