Compare commits
7 Commits
tag-stack-
...
preview-ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f0ffa0109 | ||
|
|
95d8409900 | ||
|
|
d27fdd96f2 | ||
|
|
c8e909afc6 | ||
|
|
abad6d9be9 | ||
|
|
9c50d19841 | ||
|
|
17b98d068a |
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -3203,7 +3203,9 @@ dependencies = [
|
||||
name = "component_preview"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"agent",
|
||||
"anyhow",
|
||||
"assistant_tool",
|
||||
"client",
|
||||
"collections",
|
||||
"component",
|
||||
@@ -3213,9 +3215,11 @@ dependencies = [
|
||||
"log",
|
||||
"notifications",
|
||||
"project",
|
||||
"prompt_store",
|
||||
"serde",
|
||||
"ui",
|
||||
"ui_input",
|
||||
"util",
|
||||
"workspace",
|
||||
"workspace-hack",
|
||||
]
|
||||
|
||||
@@ -973,8 +973,8 @@ mod tests {
|
||||
ThreadStore::load(
|
||||
project.clone(),
|
||||
cx.new(|_| ToolWorkingSet::default()),
|
||||
prompt_store,
|
||||
Arc::new(PromptBuilder::new(None).unwrap()),
|
||||
prompt_store,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -34,7 +34,7 @@ use prompt_store::PromptBuilder;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use settings::Settings as _;
|
||||
use thread::ThreadId;
|
||||
pub use thread::{MessageSegment, ThreadId};
|
||||
|
||||
pub use crate::active_thread::ActiveThread;
|
||||
use crate::assistant_configuration::{AddContextServerModal, ManageProfilesModal};
|
||||
@@ -42,7 +42,7 @@ pub use crate::assistant_panel::{AssistantPanel, ConcreteAssistantPanelDelegate}
|
||||
pub use crate::context::{ContextLoadResult, LoadedContext};
|
||||
pub use crate::inline_assistant::InlineAssistant;
|
||||
pub use crate::thread::{Message, Thread, ThreadEvent};
|
||||
pub use crate::thread_store::ThreadStore;
|
||||
pub use crate::thread_store::{SharedProjectContext, ThreadStore};
|
||||
pub use agent_diff::{AgentDiff, AgentDiffToolbar};
|
||||
|
||||
actions!(
|
||||
|
||||
@@ -302,8 +302,8 @@ impl AssistantPanel {
|
||||
ThreadStore::load(
|
||||
project,
|
||||
tools.clone(),
|
||||
prompt_store.clone(),
|
||||
prompt_builder.clone(),
|
||||
prompt_store.clone(),
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
|
||||
@@ -2850,8 +2850,8 @@ fn main() {{
|
||||
ThreadStore::load(
|
||||
project.clone(),
|
||||
cx.new(|_| ToolWorkingSet::default()),
|
||||
None,
|
||||
Arc::new(PromptBuilder::new(None).unwrap()),
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -81,8 +81,8 @@ impl ThreadStore {
|
||||
pub fn load(
|
||||
project: Entity<Project>,
|
||||
tools: Entity<ToolWorkingSet>,
|
||||
prompt_store: Option<Entity<PromptStore>>,
|
||||
prompt_builder: Arc<PromptBuilder>,
|
||||
prompt_store: Option<Entity<PromptStore>>,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Entity<Self>>> {
|
||||
cx.spawn(async move |cx| {
|
||||
|
||||
@@ -98,6 +98,10 @@ impl RenderOnce for UsageBanner {
|
||||
}
|
||||
|
||||
impl Component for UsageBanner {
|
||||
fn scope() -> ComponentScope {
|
||||
ComponentScope::Agent
|
||||
}
|
||||
|
||||
fn sort_name() -> &'static str {
|
||||
"AgentUsageBanner"
|
||||
}
|
||||
|
||||
@@ -15,18 +15,24 @@ path = "src/component_preview.rs"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
client.workspace = true
|
||||
collections.workspace = true
|
||||
component.workspace = true
|
||||
db.workspace = true
|
||||
gpui.workspace = true
|
||||
languages.workspace = true
|
||||
notifications.workspace = true
|
||||
log.workspace = true
|
||||
notifications.workspace = true
|
||||
project.workspace = true
|
||||
serde.workspace = true
|
||||
ui.workspace = true
|
||||
ui_input.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
workspace.workspace = true
|
||||
db.workspace = true
|
||||
anyhow.workspace = true
|
||||
serde.workspace = true
|
||||
util.workspace = true
|
||||
|
||||
# Dependencies for supporting specific previews
|
||||
agent.workspace = true
|
||||
assistant_tool.workspace = true
|
||||
prompt_store.workspace = true
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
//! A view for exploring Zed components.
|
||||
|
||||
mod persistence;
|
||||
mod preview_support;
|
||||
|
||||
use std::iter::Iterator;
|
||||
use std::sync::Arc;
|
||||
|
||||
use agent::{ActiveThread, ThreadStore};
|
||||
use client::UserStore;
|
||||
use component::{ComponentId, ComponentMetadata, components};
|
||||
use gpui::{
|
||||
@@ -19,6 +21,7 @@ use gpui::{ListState, ScrollHandle, ScrollStrategy, UniformListScrollHandle};
|
||||
use languages::LanguageRegistry;
|
||||
use notifications::status_toast::{StatusToast, ToastIcon};
|
||||
use persistence::COMPONENT_PREVIEW_DB;
|
||||
use preview_support::active_thread::{load_preview_thread_store, static_active_thread};
|
||||
use project::Project;
|
||||
use ui::{Divider, HighlightedLabel, ListItem, ListSubHeader, prelude::*};
|
||||
|
||||
@@ -33,6 +36,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut App) {
|
||||
|
||||
cx.observe_new(move |workspace: &mut Workspace, _window, cx| {
|
||||
let app_state = app_state.clone();
|
||||
let project = workspace.project().clone();
|
||||
let weak_workspace = cx.entity().downgrade();
|
||||
|
||||
workspace.register_action(
|
||||
@@ -45,6 +49,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut App) {
|
||||
let component_preview = cx.new(|cx| {
|
||||
ComponentPreview::new(
|
||||
weak_workspace.clone(),
|
||||
project.clone(),
|
||||
language_registry,
|
||||
user_store,
|
||||
None,
|
||||
@@ -52,6 +57,8 @@ pub fn init(app_state: Arc<AppState>, cx: &mut App) {
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
// TODO: don't panic here if we fail to create
|
||||
.expect("Failed to create component preview")
|
||||
});
|
||||
|
||||
workspace.add_item_to_active_pane(
|
||||
@@ -69,6 +76,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut App) {
|
||||
|
||||
enum PreviewEntry {
|
||||
AllComponents,
|
||||
ActiveThread,
|
||||
Separator,
|
||||
Component(ComponentMetadata, Option<Vec<usize>>),
|
||||
SectionHeader(SharedString),
|
||||
@@ -91,6 +99,7 @@ enum PreviewPage {
|
||||
#[default]
|
||||
AllComponents,
|
||||
Component(ComponentId),
|
||||
ActiveThread,
|
||||
}
|
||||
|
||||
struct ComponentPreview {
|
||||
@@ -105,21 +114,50 @@ struct ComponentPreview {
|
||||
cursor_index: usize,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
project: Entity<Project>,
|
||||
user_store: Entity<UserStore>,
|
||||
filter_editor: Entity<SingleLineInput>,
|
||||
filter_text: String,
|
||||
|
||||
// preview support
|
||||
thread_store: Option<Entity<ThreadStore>>,
|
||||
active_thread: Option<Entity<ActiveThread>>,
|
||||
}
|
||||
|
||||
impl ComponentPreview {
|
||||
pub fn new(
|
||||
workspace: WeakEntity<Workspace>,
|
||||
project: Entity<Project>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
user_store: Entity<UserStore>,
|
||||
selected_index: impl Into<Option<usize>>,
|
||||
active_page: Option<PreviewPage>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
) -> anyhow::Result<Self> {
|
||||
let workspace_clone = workspace.clone();
|
||||
let project_clone = project.clone();
|
||||
|
||||
let entity = cx.weak_entity();
|
||||
window
|
||||
.spawn(cx, async move |cx| {
|
||||
let thread_store_task =
|
||||
load_preview_thread_store(workspace_clone.clone(), project_clone.clone(), cx)
|
||||
.await;
|
||||
|
||||
if let Ok(thread_store) = dbg!(thread_store_task.await) {
|
||||
entity
|
||||
.update_in(cx, |this, window, cx| {
|
||||
this.thread_store = Some(thread_store.clone());
|
||||
this.create_active_thread(window, cx);
|
||||
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
let sorted_components = components().all_sorted();
|
||||
let selected_index = selected_index.into().unwrap_or(0);
|
||||
let active_page = active_page.unwrap_or(PreviewPage::AllComponents);
|
||||
@@ -151,6 +189,7 @@ impl ComponentPreview {
|
||||
language_registry,
|
||||
user_store,
|
||||
workspace,
|
||||
project,
|
||||
active_page,
|
||||
component_map: components().0,
|
||||
components: sorted_components,
|
||||
@@ -158,6 +197,8 @@ impl ComponentPreview {
|
||||
cursor_index: selected_index,
|
||||
filter_editor,
|
||||
filter_text: String::new(),
|
||||
thread_store: None,
|
||||
active_thread: None,
|
||||
};
|
||||
|
||||
if component_preview.cursor_index > 0 {
|
||||
@@ -169,13 +210,36 @@ impl ComponentPreview {
|
||||
let focus_handle = component_preview.filter_editor.read(cx).focus_handle(cx);
|
||||
window.focus(&focus_handle);
|
||||
|
||||
component_preview
|
||||
dbg!(component_preview.thread_store.clone());
|
||||
|
||||
Ok(component_preview)
|
||||
}
|
||||
|
||||
pub fn create_active_thread(
|
||||
&mut self,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> &mut Self {
|
||||
println!("Creating active thread");
|
||||
let workspace = self.workspace.clone();
|
||||
let language_registry = self.language_registry.clone();
|
||||
if let Some(thread_store) = self.thread_store.clone() {
|
||||
let active_thread =
|
||||
static_active_thread(workspace, language_registry, thread_store, window, cx);
|
||||
self.active_thread = Some(active_thread);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
dbg!(self.active_thread.clone());
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn active_page_id(&self, _cx: &App) -> ActivePageId {
|
||||
match &self.active_page {
|
||||
PreviewPage::AllComponents => ActivePageId::default(),
|
||||
PreviewPage::Component(component_id) => ActivePageId(component_id.0.to_string()),
|
||||
PreviewPage::ActiveThread => ActivePageId("active_thread".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,6 +353,7 @@ impl ComponentPreview {
|
||||
|
||||
// Always show all components first
|
||||
entries.push(PreviewEntry::AllComponents);
|
||||
entries.push(PreviewEntry::ActiveThread);
|
||||
entries.push(PreviewEntry::Separator);
|
||||
|
||||
let mut scopes: Vec<_> = scope_groups
|
||||
@@ -389,6 +454,19 @@ impl ComponentPreview {
|
||||
}))
|
||||
.into_any_element()
|
||||
}
|
||||
PreviewEntry::ActiveThread => {
|
||||
let selected = self.active_page == PreviewPage::ActiveThread;
|
||||
|
||||
ListItem::new(ix)
|
||||
.child(Label::new("Active Thread").color(Color::Default))
|
||||
.selectable(true)
|
||||
.toggle_state(selected)
|
||||
.inset(true)
|
||||
.on_click(cx.listener(move |this, _, _, cx| {
|
||||
this.set_active_page(PreviewPage::ActiveThread, cx);
|
||||
}))
|
||||
.into_any_element()
|
||||
}
|
||||
PreviewEntry::Separator => ListItem::new(ix)
|
||||
.child(
|
||||
h_flex()
|
||||
@@ -471,6 +549,7 @@ impl ComponentPreview {
|
||||
.render_scope_header(ix, shared_string.clone(), window, cx)
|
||||
.into_any_element(),
|
||||
PreviewEntry::AllComponents => div().w_full().h_0().into_any_element(),
|
||||
PreviewEntry::ActiveThread => div().w_full().h_0().into_any_element(),
|
||||
PreviewEntry::Separator => div().w_full().h_0().into_any_element(),
|
||||
})
|
||||
.unwrap()
|
||||
@@ -595,6 +674,19 @@ impl ComponentPreview {
|
||||
}
|
||||
}
|
||||
|
||||
fn render_active_thread(&self, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
dbg!(&self.active_thread);
|
||||
|
||||
v_flex()
|
||||
.id("render-active-thread")
|
||||
.size_full()
|
||||
.children(self.active_thread.clone().map(|thread| thread.clone()))
|
||||
.when_none(&self.active_thread.clone(), |this| {
|
||||
this.child("No active thread")
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn test_status_toast(&self, cx: &mut Context<Self>) {
|
||||
if let Some(workspace) = self.workspace.upgrade() {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
@@ -704,6 +796,9 @@ impl Render for ComponentPreview {
|
||||
PreviewPage::Component(id) => self
|
||||
.render_component_page(&id, window, cx)
|
||||
.into_any_element(),
|
||||
PreviewPage::ActiveThread => {
|
||||
self.render_active_thread(cx).into_any_element()
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -759,12 +854,14 @@ impl Item for ComponentPreview {
|
||||
let language_registry = self.language_registry.clone();
|
||||
let user_store = self.user_store.clone();
|
||||
let weak_workspace = self.workspace.clone();
|
||||
let project = self.project.clone();
|
||||
let selected_index = self.cursor_index;
|
||||
let active_page = self.active_page.clone();
|
||||
|
||||
Some(cx.new(|cx| {
|
||||
Self::new(
|
||||
weak_workspace,
|
||||
project,
|
||||
language_registry,
|
||||
user_store,
|
||||
selected_index,
|
||||
@@ -772,6 +869,7 @@ impl Item for ComponentPreview {
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
.expect("Failed to create new component preview")
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -838,10 +936,12 @@ impl SerializableItem for ComponentPreview {
|
||||
let user_store = user_store.clone();
|
||||
let language_registry = language_registry.clone();
|
||||
let weak_workspace = workspace.clone();
|
||||
let project = project.clone();
|
||||
cx.update(move |window, cx| {
|
||||
Ok(cx.new(|cx| {
|
||||
ComponentPreview::new(
|
||||
weak_workspace,
|
||||
project,
|
||||
language_registry,
|
||||
user_store,
|
||||
None,
|
||||
@@ -849,6 +949,7 @@ impl SerializableItem for ComponentPreview {
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
.expect("Failed to create new component preview")
|
||||
}))
|
||||
})?
|
||||
})
|
||||
|
||||
1
crates/component_preview/src/preview_support.rs
Normal file
1
crates/component_preview/src/preview_support.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod active_thread;
|
||||
@@ -0,0 +1,64 @@
|
||||
use languages::LanguageRegistry;
|
||||
use project::Project;
|
||||
use std::sync::Arc;
|
||||
|
||||
use agent::{ActiveThread, MessageSegment, ThreadStore};
|
||||
use assistant_tool::ToolWorkingSet;
|
||||
use gpui::{AppContext, AsyncApp, Entity, Task, WeakEntity};
|
||||
use prompt_store::PromptBuilder;
|
||||
use ui::{App, Window};
|
||||
use workspace::Workspace;
|
||||
|
||||
pub async fn load_preview_thread_store(
|
||||
workspace: WeakEntity<Workspace>,
|
||||
project: Entity<Project>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Task<anyhow::Result<Entity<ThreadStore>>> {
|
||||
cx.spawn(async move |cx| {
|
||||
workspace
|
||||
.update(cx, |_, cx| {
|
||||
ThreadStore::load(
|
||||
project.clone(),
|
||||
cx.new(|_| ToolWorkingSet::default()),
|
||||
Arc::new(PromptBuilder::new(None).unwrap()),
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await
|
||||
})
|
||||
}
|
||||
|
||||
pub fn static_active_thread(
|
||||
workspace: WeakEntity<Workspace>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
thread_store: Entity<ThreadStore>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Entity<ActiveThread> {
|
||||
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()),
|
||||
], cx);
|
||||
});
|
||||
cx.new(|cx| {
|
||||
ActiveThread::new(
|
||||
thread,
|
||||
thread_store,
|
||||
language_registry,
|
||||
workspace.clone(),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -222,8 +222,8 @@ impl ExampleInstance {
|
||||
let thread_store = ThreadStore::load(
|
||||
project.clone(),
|
||||
tools,
|
||||
prompt_store,
|
||||
app_state.prompt_builder.clone(),
|
||||
prompt_store,
|
||||
cx,
|
||||
);
|
||||
let meta = self.thread.meta();
|
||||
|
||||
Reference in New Issue
Block a user