diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index f4da3078add322..4650df181d3369 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -212,7 +212,8 @@ "context": "AssistantChat > Editor", // Used in the assistant2 crate "bindings": { "enter": ["assistant2::Submit", "Simple"], - "cmd-enter": ["assistant2::Submit", "Codebase"] + "cmd-enter": ["assistant2::Submit", "Codebase"], + "escape": "assistant2::Cancel" } }, { diff --git a/crates/assistant2/src/assistant2.rs b/crates/assistant2/src/assistant2.rs index 683ce911af7afb..b89291bd133e52 100644 --- a/crates/assistant2/src/assistant2.rs +++ b/crates/assistant2/src/assistant2.rs @@ -34,8 +34,6 @@ pub use assistant_settings::AssistantSettings; const MAX_COMPLETION_CALLS_PER_SUBMISSION: usize = 5; -// gpui::actions!(assistant, [Submit]); - #[derive(Eq, PartialEq, Copy, Clone, Deserialize)] pub struct Submit(SubmitMode); @@ -50,7 +48,7 @@ pub enum SubmitMode { Codebase, } -gpui::actions!(assistant2, [ToggleFocus]); +gpui::actions!(assistant2, [Cancel, ToggleFocus]); gpui::impl_actions!(assistant2, [Submit]); pub fn init(client: Arc, cx: &mut AppContext) { @@ -256,6 +254,21 @@ impl AssistantChat { }) } + fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { + if self.pending_completion.take().is_none() { + cx.propagate(); + return; + } + + if let Some(ChatMessage::Assistant(message)) = self.messages.last() { + if message.body.text.is_empty() { + self.pop_message(cx); + } else { + self.push_new_user_message(false, cx); + } + } + } + fn submit(&mut self, Submit(mode): &Submit, cx: &mut ViewContext) { let Some(focused_message_id) = self.focused_message_id(cx) else { log::error!("unexpected state: no user message editor is focused."); @@ -282,6 +295,7 @@ impl AssistantChat { .focus_handle(cx) .contains_focused(cx); this.push_new_user_message(focus, cx); + this.pending_completion = None; }) .context("Failed to push new user message") .log_err(); @@ -453,6 +467,17 @@ impl AssistantChat { cx.notify(); } + fn pop_message(&mut self, cx: &mut ViewContext) { + if self.messages.is_empty() { + return; + } + + self.messages.pop(); + self.list_state + .splice(self.messages.len()..self.messages.len() + 1, 0); + cx.notify(); + } + fn truncate_messages(&mut self, last_message_id: MessageId, cx: &mut ViewContext) { if let Some(index) = self.messages.iter().position(|message| match message { ChatMessage::User(message) => message.id == last_message_id, @@ -677,6 +702,7 @@ impl Render for AssistantChat { .flex_1() .v_flex() .key_context("AssistantChat") + .on_action(cx.listener(Self::cancel)) .text_color(Color::Default.color(cx)) .child(self.render_model_dropdown(cx)) .child(list(self.list_state.clone()).flex_1())