agent: Scroll to bottom after submitting a new message (#32819)

Danilo Leal created

This is a follow up to my original attempt
https://github.com/zed-industries/zed/pull/30878 and to the PR that
eventually reverted parts of it because it broke stuff
https://github.com/zed-industries/zed/pull/31295. This new approach
attaches the `scroll_to_bottom` feature to the `chat` function, which is
triggered when the `Chat` action is dispatched by the "send" icon
buttons. With that, and from my testing, the thread doesn't forcefully
scroll as new messages are added, which was the regression I had
introduced.

Release Notes:

- agent: The panel nows scrolls to the bottom after submitting a new
message, allowing to see it more easily.

Change summary

crates/agent/src/agent_panel.rs    | 21 ++++++++++++++++++---
crates/agent/src/message_editor.rs |  6 ++++--
2 files changed, 22 insertions(+), 5 deletions(-)

Detailed changes

crates/agent/src/agent_panel.rs 🔗

@@ -520,10 +520,15 @@ impl AgentPanel {
         });
 
         let message_editor_subscription =
-            cx.subscribe(&message_editor, |_, _, event, cx| match event {
+            cx.subscribe(&message_editor, |this, _, event, cx| match event {
                 MessageEditorEvent::Changed | MessageEditorEvent::EstimatedTokenCount => {
                     cx.notify();
                 }
+                MessageEditorEvent::ScrollThreadToBottom => {
+                    this.thread.update(cx, |thread, cx| {
+                        thread.scroll_to_bottom(cx);
+                    });
+                }
             });
 
         let thread_id = thread.read(cx).id().clone();
@@ -803,10 +808,15 @@ impl AgentPanel {
         self.message_editor.focus_handle(cx).focus(window);
 
         let message_editor_subscription =
-            cx.subscribe(&self.message_editor, |_, _, event, cx| match event {
+            cx.subscribe(&self.message_editor, |this, _, event, cx| match event {
                 MessageEditorEvent::Changed | MessageEditorEvent::EstimatedTokenCount => {
                     cx.notify();
                 }
+                MessageEditorEvent::ScrollThreadToBottom => {
+                    this.thread.update(cx, |thread, cx| {
+                        thread.scroll_to_bottom(cx);
+                    });
+                }
             });
 
         self._active_thread_subscriptions = vec![
@@ -1018,10 +1028,15 @@ impl AgentPanel {
         self.message_editor.focus_handle(cx).focus(window);
 
         let message_editor_subscription =
-            cx.subscribe(&self.message_editor, |_, _, event, cx| match event {
+            cx.subscribe(&self.message_editor, |this, _, event, cx| match event {
                 MessageEditorEvent::Changed | MessageEditorEvent::EstimatedTokenCount => {
                     cx.notify();
                 }
+                MessageEditorEvent::ScrollThreadToBottom => {
+                    this.thread.update(cx, |thread, cx| {
+                        thread.scroll_to_bottom(cx);
+                    });
+                }
             });
 
         self._active_thread_subscriptions = vec![

crates/agent/src/message_editor.rs 🔗

@@ -301,6 +301,7 @@ impl MessageEditor {
         self.set_editor_is_expanded(false, cx);
         self.send_to_model(window, cx);
 
+        cx.emit(MessageEditorEvent::ScrollThreadToBottom);
         cx.notify();
     }
 
@@ -906,7 +907,7 @@ impl MessageEditor {
             )
     }
 
-    fn render_changed_buffers(
+    fn render_edits_bar(
         &self,
         changed_buffers: &BTreeMap<Entity<Buffer>, Entity<BufferDiff>>,
         window: &mut Window,
@@ -1510,6 +1511,7 @@ impl EventEmitter<MessageEditorEvent> for MessageEditor {}
 pub enum MessageEditorEvent {
     EstimatedTokenCount,
     Changed,
+    ScrollThreadToBottom,
 }
 
 impl Focusable for MessageEditor {
@@ -1537,7 +1539,7 @@ impl Render for MessageEditor {
         v_flex()
             .size_full()
             .when(changed_buffers.len() > 0, |parent| {
-                parent.child(self.render_changed_buffers(&changed_buffers, window, cx))
+                parent.child(self.render_edits_bar(&changed_buffers, window, cx))
             })
             .child(self.render_editor(window, cx))
             .children({