Allow Escape to interrupt agent thread from conversation focus (#46410)
When focus is on the conversation part of the agent panel (not the message editor), pressing Escape now interrupts the running thread. Previously, Escape only worked when the message editor had focus. Release Notes: - Pressing Esc when the agent panel is focused now interrupts the running thread even if the text input box is not specifically focused.
This commit is contained in:
1 parent
29d2c12f3e
commit
c47dd73349
4 files changed
+142
-2
No files matched your search
@@ -13,7 +13,7 @@ path = "src/agent_ui.rs"
|
||||
doctest = false
|
||||
|
||||
[features]
|
||||
test-support = ["assistant_text_thread/test-support", "acp_thread/test-support", "eval_utils", "gpui/test-support", "language/test-support", "reqwest_client", "workspace/test-support", "agent/test-support"]
|
||||
test-support = ["assistant_text_thread/test-support", "acp_thread/test-support", "eval_utils", "gpui/test-support", "language/test-support", "reqwest_client", "workspace/test-support", "agent/test-support", "rules_library/test-support"]
|
||||
unit-eval = []
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -6903,6 +6903,9 @@ impl Render for AcpThreadView {
|
||||
v_flex()
|
||||
.size_full()
|
||||
.key_context("AcpThread")
|
||||
.on_action(cx.listener(|this, _: &menu::Cancel, _, cx| {
|
||||
this.cancel_generation(cx);
|
||||
}))
|
||||
.on_action(cx.listener(Self::toggle_burn_mode))
|
||||
.on_action(cx.listener(Self::keep_all))
|
||||
.on_action(cx.listener(Self::reject_all))
|
||||
@@ -8224,6 +8227,140 @@ pub(crate) mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
struct GeneratingThreadSetup {
|
||||
thread_view: Entity<AcpThreadView>,
|
||||
thread: Entity<AcpThread>,
|
||||
message_editor: Entity<MessageEditor>,
|
||||
}
|
||||
|
||||
async fn setup_generating_thread(
|
||||
cx: &mut TestAppContext,
|
||||
) -> (GeneratingThreadSetup, &mut VisualTestContext) {
|
||||
let connection = StubAgentConnection::new();
|
||||
|
||||
let (thread_view, cx) =
|
||||
setup_thread_view(StubAgentServer::new(connection.clone()), cx).await;
|
||||
add_to_workspace(thread_view.clone(), cx);
|
||||
|
||||
let message_editor = cx.read(|cx| thread_view.read(cx).message_editor.clone());
|
||||
message_editor.update_in(cx, |editor, window, cx| {
|
||||
editor.set_text("Hello", window, cx);
|
||||
});
|
||||
thread_view.update_in(cx, |thread_view, window, cx| {
|
||||
thread_view.send(window, cx);
|
||||
});
|
||||
|
||||
let (thread, session_id) = thread_view.read_with(cx, |view, cx| {
|
||||
let thread = view.thread().unwrap();
|
||||
(thread.clone(), thread.read(cx).session_id().clone())
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update(|_, cx| {
|
||||
connection.send_update(
|
||||
session_id.clone(),
|
||||
acp::SessionUpdate::AgentMessageChunk(acp::ContentChunk::new(
|
||||
"Response chunk".into(),
|
||||
)),
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
thread.read_with(cx, |thread, _cx| {
|
||||
assert_eq!(thread.status(), ThreadStatus::Generating);
|
||||
});
|
||||
|
||||
(
|
||||
GeneratingThreadSetup {
|
||||
thread_view,
|
||||
thread,
|
||||
message_editor,
|
||||
},
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_escape_cancels_generation_from_conversation_focus(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let (setup, cx) = setup_generating_thread(cx).await;
|
||||
|
||||
let focus_handle = setup
|
||||
.thread_view
|
||||
.read_with(cx, |view, _cx| view.focus_handle.clone());
|
||||
cx.update(|window, cx| {
|
||||
window.focus(&focus_handle, cx);
|
||||
});
|
||||
|
||||
setup.thread_view.update_in(cx, |_, window, cx| {
|
||||
window.dispatch_action(menu::Cancel.boxed_clone(), cx);
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
setup.thread.read_with(cx, |thread, _cx| {
|
||||
assert_eq!(thread.status(), ThreadStatus::Idle);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_escape_cancels_generation_from_editor_focus(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let (setup, cx) = setup_generating_thread(cx).await;
|
||||
|
||||
let editor_focus_handle = setup
|
||||
.message_editor
|
||||
.read_with(cx, |editor, cx| editor.focus_handle(cx));
|
||||
cx.update(|window, cx| {
|
||||
window.focus(&editor_focus_handle, cx);
|
||||
});
|
||||
|
||||
setup.message_editor.update_in(cx, |_, window, cx| {
|
||||
window.dispatch_action(editor::actions::Cancel.boxed_clone(), cx);
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
setup.thread.read_with(cx, |thread, _cx| {
|
||||
assert_eq!(thread.status(), ThreadStatus::Idle);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_escape_when_idle_is_noop(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let (thread_view, cx) =
|
||||
setup_thread_view(StubAgentServer::new(StubAgentConnection::new()), cx).await;
|
||||
add_to_workspace(thread_view.clone(), cx);
|
||||
|
||||
let thread = thread_view.read_with(cx, |view, _cx| view.thread().unwrap().clone());
|
||||
|
||||
thread.read_with(cx, |thread, _cx| {
|
||||
assert_eq!(thread.status(), ThreadStatus::Idle);
|
||||
});
|
||||
|
||||
let focus_handle = thread_view.read_with(cx, |view, _cx| view.focus_handle.clone());
|
||||
cx.update(|window, cx| {
|
||||
window.focus(&focus_handle, cx);
|
||||
});
|
||||
|
||||
thread_view.update_in(cx, |_, window, cx| {
|
||||
window.dispatch_action(menu::Cancel.boxed_clone(), cx);
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
thread.read_with(cx, |thread, _cx| {
|
||||
assert_eq!(thread.status(), ThreadStatus::Idle);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_interrupt(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
@@ -14,7 +14,7 @@ doctest = false
|
||||
|
||||
[features]
|
||||
default = []
|
||||
test-support = ["remote/test-support"]
|
||||
test-support = ["remote/test-support", "project/test-support", "workspace/test-support"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
|
||||
@@ -11,6 +11,9 @@ workspace = true
|
||||
[lib]
|
||||
path = "src/rules_library.rs"
|
||||
|
||||
[features]
|
||||
test-support = ["title_bar/test-support"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
collections.workspace = true
|
||||
|
||||
Reference in new issue
Block a user