Use a single Text segment + indoc! in active thread preview (#30373)

Michael Sloan created

Release Notes:

- N/A

Change summary

Cargo.lock                                                    |  1 
crates/component_preview/Cargo.toml                           |  3 
crates/component_preview/src/preview_support/active_thread.rs | 42 +++-
3 files changed, 31 insertions(+), 15 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -3196,6 +3196,7 @@ dependencies = [
  "db",
  "futures 0.3.31",
  "gpui",
+ "indoc",
  "languages",
  "log",
  "notifications",

crates/component_preview/Cargo.toml 🔗

@@ -17,12 +17,14 @@ default = []
 [dependencies]
 agent.workspace = true
 anyhow.workspace = true
+assistant_tool.workspace = true
 client.workspace = true
 collections.workspace = true
 component.workspace = true
 db.workspace = true
 futures.workspace = true
 gpui.workspace = true
+indoc.workspace = true
 languages.workspace = true
 log.workspace = true
 notifications.workspace = true
@@ -34,4 +36,3 @@ ui_input.workspace = true
 util.workspace = true
 workspace-hack.workspace = true
 workspace.workspace = true
-assistant_tool.workspace = true

crates/component_preview/src/preview_support/active_thread.rs 🔗

@@ -1,12 +1,12 @@
-use languages::LanguageRegistry;
-use project::Project;
-use std::sync::Arc;
-
 use agent::{ActiveThread, ContextStore, MessageSegment, TextThreadStore, ThreadStore};
 use anyhow::{Result, anyhow};
 use assistant_tool::ToolWorkingSet;
 use gpui::{AppContext, AsyncApp, Entity, Task, WeakEntity};
+use indoc::indoc;
+use languages::LanguageRegistry;
+use project::Project;
 use prompt_store::PromptBuilder;
+use std::sync::Arc;
 use ui::{App, Window};
 use workspace::Workspace;
 
@@ -60,16 +60,30 @@ pub fn static_active_thread(
     let thread = thread_store.update(cx, |thread_store, cx| thread_store.create_thread(cx));
     thread.update(cx, |thread, cx| {
         thread.insert_assistant_message(vec![
-            MessageSegment::Text("I'll help you fix the lifetime error in your `cx.spawn` call. When working with async operations in GPUI, there are specific patterns to follow for proper lifetime management.".to_string()),
-            MessageSegment::Text("\n\nLet's look at what's happening in your code:".to_string()),
-            MessageSegment::Text("\n\n---\n\nLet's check the current state of the active_thread.rs file to understand what might have changed:".to_string()),
-            MessageSegment::Text("\n\n---\n\nLooking at the implementation of `load_preview_thread_store` and understanding GPUI's async patterns, here's the issue:".to_string()),
-            MessageSegment::Text("\n\n1. `load_preview_thread_store` returns a `Task<anyhow::Result<Entity<ThreadStore>>>`, which means it's already a task".to_string()),
-            MessageSegment::Text("\n2. When you call this function inside another `spawn` call, you're nesting tasks incorrectly".to_string()),
-            MessageSegment::Text("\n3. The `this` parameter you're trying to use in your closure has the wrong context".to_string()),
-            MessageSegment::Text("\n\nHere's the correct way to implement this:".to_string()),
-            MessageSegment::Text("\n\n---\n\nThe problem is in how you're setting up the async closure and trying to reference variables like `window` and `language_registry` that aren't accessible in that scope.".to_string()),
-            MessageSegment::Text("\n\nHere's how to fix it:".to_string()),
+            MessageSegment::Text(indoc! {"
+                I'll help you fix the lifetime error in your `cx.spawn` call. When working with async operations in GPUI, there are specific patterns to follow for proper lifetime management.
+
+                Let's look at what's happening in your code:
+
+                ---
+
+                Let's check the current state of the active_thread.rs file to understand what might have changed:
+
+                ---
+
+                Looking at the implementation of `load_preview_thread_store` and understanding GPUI's async patterns, here's the issue:
+
+                1. `load_preview_thread_store` returns a `Task<anyhow::Result<Entity<ThreadStore>>>`, which means it's already a task.
+                2. When you call this function inside another `spawn` call, you're nesting tasks incorrectly.
+
+                Here's the correct way to implement this:
+
+                ---
+
+                The problem is in how you're setting up the async closure and trying to reference variables like `window` and `language_registry` that aren't accessible in that scope.
+
+                Here's how to fix it:
+            "}.to_string()),
         ], cx);
     });
     cx.new(|cx| {