assistant2: Use composer for editing inline messages (#11222)
This PR updates the assistant to render historical user messages the same as ones from the assistant. Double-clicking on a message will open a composer inline for editing. Pressing `Esc` will cancel the edit. We don't yet restore the previous state of the message upon canceling. <img width="401" alt="Screenshot 2024-04-30 at 4 04 01 PM" src="https://github.com/zed-industries/zed/assets/1486634/5f253fa8-6578-4054-be30-c495e326d700"> <img width="401" alt="Screenshot 2024-04-30 at 4 04 28 PM" src="https://github.com/zed-industries/zed/assets/1486634/edf25cea-d97e-44d2-8772-3690eac017a4"> Release Notes: - N/A
This commit is contained in:
parent
e8ee0131f1
commit
f11a7811f3
1 changed files with 49 additions and 14 deletions
|
@ -13,8 +13,8 @@ use editor::Editor;
|
||||||
use feature_flags::FeatureFlagAppExt as _;
|
use feature_flags::FeatureFlagAppExt as _;
|
||||||
use futures::{future::join_all, StreamExt};
|
use futures::{future::join_all, StreamExt};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
list, AnyElement, AppContext, AsyncWindowContext, EventEmitter, FocusHandle, FocusableView,
|
list, AnyElement, AppContext, AsyncWindowContext, ClickEvent, EventEmitter, FocusHandle,
|
||||||
ListAlignment, ListState, Model, Render, Task, View, WeakView,
|
FocusableView, ListAlignment, ListState, Model, Render, Task, View, WeakView,
|
||||||
};
|
};
|
||||||
use language::{language_settings::SoftWrap, LanguageRegistry};
|
use language::{language_settings::SoftWrap, LanguageRegistry};
|
||||||
use open_ai::{FunctionContent, ToolCall, ToolCallContent};
|
use open_ai::{FunctionContent, ToolCall, ToolCallContent};
|
||||||
|
@ -231,6 +231,7 @@ struct AssistantChat {
|
||||||
user_store: Model<UserStore>,
|
user_store: Model<UserStore>,
|
||||||
next_message_id: MessageId,
|
next_message_id: MessageId,
|
||||||
collapsed_messages: HashMap<MessageId, bool>,
|
collapsed_messages: HashMap<MessageId, bool>,
|
||||||
|
editing_message_id: Option<MessageId>,
|
||||||
pending_completion: Option<Task<()>>,
|
pending_completion: Option<Task<()>>,
|
||||||
tool_registry: Arc<ToolRegistry>,
|
tool_registry: Arc<ToolRegistry>,
|
||||||
project_index: Option<Model<ProjectIndex>>,
|
project_index: Option<Model<ProjectIndex>>,
|
||||||
|
@ -270,6 +271,7 @@ impl AssistantChat {
|
||||||
language_registry,
|
language_registry,
|
||||||
project_index,
|
project_index,
|
||||||
next_message_id: MessageId(0),
|
next_message_id: MessageId(0),
|
||||||
|
editing_message_id: None,
|
||||||
collapsed_messages: HashMap::default(),
|
collapsed_messages: HashMap::default(),
|
||||||
pending_completion: None,
|
pending_completion: None,
|
||||||
tool_registry,
|
tool_registry,
|
||||||
|
@ -288,6 +290,9 @@ impl AssistantChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
||||||
|
// If we're currently editing a message, cancel the edit.
|
||||||
|
self.editing_message_id.take();
|
||||||
|
|
||||||
if self.pending_completion.take().is_none() {
|
if self.pending_completion.take().is_none() {
|
||||||
cx.propagate();
|
cx.propagate();
|
||||||
return;
|
return;
|
||||||
|
@ -564,19 +569,49 @@ impl AssistantChat {
|
||||||
|
|
||||||
match &self.messages[ix] {
|
match &self.messages[ix] {
|
||||||
ChatMessage::User(UserMessage { id, body }) => div()
|
ChatMessage::User(UserMessage { id, body }) => div()
|
||||||
|
.id(SharedString::from(format!("message-{}-container", id.0)))
|
||||||
.when(!is_last, |element| element.mb_2())
|
.when(!is_last, |element| element.mb_2())
|
||||||
.child(crate::ui::ChatMessage::new(
|
.map(|element| {
|
||||||
*id,
|
if self.editing_message_id.as_ref() == Some(id) {
|
||||||
UserOrAssistant::User(self.user_store.read(cx).current_user()),
|
element.child(Composer::new(
|
||||||
Some(body.clone().into_any_element()),
|
cx.view().downgrade(),
|
||||||
self.is_message_collapsed(id),
|
self.model.clone(),
|
||||||
Box::new(cx.listener({
|
body.clone(),
|
||||||
let id = *id;
|
self.user_store.read(cx).current_user(),
|
||||||
move |assistant_chat, _event, _cx| {
|
self.can_submit(),
|
||||||
assistant_chat.toggle_message_collapsed(id)
|
self.tool_registry.clone(),
|
||||||
}
|
))
|
||||||
})),
|
} else {
|
||||||
))
|
element
|
||||||
|
.on_click(cx.listener({
|
||||||
|
let id = *id;
|
||||||
|
move |assistant_chat, event: &ClickEvent, _cx| {
|
||||||
|
if event.up.click_count == 2 {
|
||||||
|
assistant_chat.editing_message_id = Some(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.child(crate::ui::ChatMessage::new(
|
||||||
|
*id,
|
||||||
|
UserOrAssistant::User(self.user_store.read(cx).current_user()),
|
||||||
|
Some(
|
||||||
|
RichText::new(
|
||||||
|
body.read(cx).text(cx),
|
||||||
|
&[],
|
||||||
|
&self.language_registry,
|
||||||
|
)
|
||||||
|
.element(ElementId::from(id.0), cx),
|
||||||
|
),
|
||||||
|
self.is_message_collapsed(id),
|
||||||
|
Box::new(cx.listener({
|
||||||
|
let id = *id;
|
||||||
|
move |assistant_chat, _event, _cx| {
|
||||||
|
assistant_chat.toggle_message_collapsed(id)
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
.into_any(),
|
.into_any(),
|
||||||
ChatMessage::Assistant(AssistantMessage {
|
ChatMessage::Assistant(AssistantMessage {
|
||||||
id,
|
id,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue