assistant2: Cancel generation button (#23137)

Turns the "esc to cancel" label into a button so it can be dispatched
via click or keyboard. The keybinding isn't hardcoded anymore.

![CleanShot 2025-01-14 at 13 44
22@2x](https://github.com/user-attachments/assets/a947f58b-7de2-400b-b95a-384b78c79697)


Release Notes:

- N/A
This commit is contained in:
Agus Zubiaga 2025-01-14 16:22:48 -03:00 committed by GitHub
parent 4febc7ea49
commit de5f023477
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 15 deletions

View file

@ -5,16 +5,16 @@ use assistant_tool::ToolWorkingSet;
use collections::HashMap; use collections::HashMap;
use gpui::{ use gpui::{
list, percentage, AbsoluteLength, Animation, AnimationExt, AnyElement, AppContext, list, percentage, AbsoluteLength, Animation, AnimationExt, AnyElement, AppContext,
DefiniteLength, EdgesRefinement, Empty, Length, ListAlignment, ListOffset, ListState, Model, DefiniteLength, EdgesRefinement, Empty, FocusHandle, Length, ListAlignment, ListOffset,
StyleRefinement, Subscription, TextStyleRefinement, Transformation, UnderlineStyle, View, ListState, Model, StyleRefinement, Subscription, TextStyleRefinement, Transformation,
WeakView, UnderlineStyle, View, WeakView,
}; };
use language::LanguageRegistry; use language::LanguageRegistry;
use language_model::Role; use language_model::Role;
use markdown::{Markdown, MarkdownStyle}; use markdown::{Markdown, MarkdownStyle};
use settings::Settings as _; use settings::Settings as _;
use theme::ThemeSettings; use theme::ThemeSettings;
use ui::prelude::*; use ui::{prelude::*, ButtonLike, KeyBinding};
use workspace::Workspace; use workspace::Workspace;
use crate::thread::{MessageId, Thread, ThreadError, ThreadEvent}; use crate::thread::{MessageId, Thread, ThreadError, ThreadEvent};
@ -29,6 +29,7 @@ pub struct ActiveThread {
list_state: ListState, list_state: ListState,
rendered_messages_by_id: HashMap<MessageId, View<Markdown>>, rendered_messages_by_id: HashMap<MessageId, View<Markdown>>,
last_error: Option<ThreadError>, last_error: Option<ThreadError>,
focus_handle: FocusHandle,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
@ -38,6 +39,7 @@ impl ActiveThread {
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
language_registry: Arc<LanguageRegistry>, language_registry: Arc<LanguageRegistry>,
tools: Arc<ToolWorkingSet>, tools: Arc<ToolWorkingSet>,
focus_handle: FocusHandle,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let subscriptions = vec![ let subscriptions = vec![
@ -60,6 +62,7 @@ impl ActiveThread {
} }
}), }),
last_error: None, last_error: None,
focus_handle,
_subscriptions: subscriptions, _subscriptions: subscriptions,
}; };
@ -345,6 +348,8 @@ impl Render for ActiveThread {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let is_streaming_completion = self.thread.read(cx).is_streaming(); let is_streaming_completion = self.thread.read(cx).is_streaming();
let focus_handle = self.focus_handle.clone();
v_flex() v_flex()
.size_full() .size_full()
.child(list(self.list_state.clone()).flex_grow()) .child(list(self.list_state.clone()).flex_grow())
@ -363,7 +368,23 @@ impl Render for ActiveThread {
.rounded_md() .rounded_md()
.bg(cx.theme().colors().elevated_surface_background) .bg(cx.theme().colors().elevated_surface_background)
.child(Label::new("Generating…").size(LabelSize::Small)) .child(Label::new("Generating…").size(LabelSize::Small))
.child(Label::new("esc to cancel").size(LabelSize::Small)), .child(
ButtonLike::new("cancel-generation")
.style(ButtonStyle::Filled)
.child(Label::new("Cancel").size(LabelSize::Small))
.children(
KeyBinding::for_action_in(
&editor::actions::Cancel,
&self.focus_handle,
cx,
)
.map(|binding| binding.into_any_element()),
)
.on_click(move |_event, cx| {
focus_handle
.dispatch_action(&editor::actions::Cancel, cx);
}),
),
) )
}), }),
) )

View file

@ -100,6 +100,16 @@ impl AssistantPanel {
let workspace = workspace.weak_handle(); let workspace = workspace.weak_handle();
let weak_self = cx.view().downgrade(); let weak_self = cx.view().downgrade();
let message_editor = cx.new_view(|cx| {
MessageEditor::new(
fs.clone(),
workspace.clone(),
thread_store.downgrade(),
thread.clone(),
cx,
)
});
Self { Self {
active_view: ActiveView::Thread, active_view: ActiveView::Thread,
workspace: workspace.clone(), workspace: workspace.clone(),
@ -109,21 +119,14 @@ impl AssistantPanel {
thread: cx.new_view(|cx| { thread: cx.new_view(|cx| {
ActiveThread::new( ActiveThread::new(
thread.clone(), thread.clone(),
workspace.clone(), workspace,
language_registry, language_registry,
tools.clone(), tools.clone(),
message_editor.focus_handle(cx),
cx, cx,
) )
}), }),
message_editor: cx.new_view(|cx| { message_editor,
MessageEditor::new(
fs.clone(),
workspace,
thread_store.downgrade(),
thread.clone(),
cx,
)
}),
tools, tools,
local_timezone: UtcOffset::from_whole_seconds( local_timezone: UtcOffset::from_whole_seconds(
chrono::Local::now().offset().local_minus_utc(), chrono::Local::now().offset().local_minus_utc(),
@ -160,6 +163,7 @@ impl AssistantPanel {
self.workspace.clone(), self.workspace.clone(),
self.language_registry.clone(), self.language_registry.clone(),
self.tools.clone(), self.tools.clone(),
self.focus_handle(cx),
cx, cx,
) )
}); });
@ -196,6 +200,7 @@ impl AssistantPanel {
self.workspace.clone(), self.workspace.clone(),
self.language_registry.clone(), self.language_registry.clone(),
self.tools.clone(), self.tools.clone(),
self.focus_handle(cx),
cx, cx,
) )
}); });