From 5395197619f612aef59bd80a1108de294cc2aa77 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 19 Dec 2025 16:34:14 -0800 Subject: [PATCH] Separate out component_preview crate and add easy-to-use example binaries (#45382) Release Notes: - N/A --- Cargo.lock | 29 +++- Cargo.toml | 2 + crates/component_preview/Cargo.toml | 45 ++++++ crates/component_preview/LICENSE-GPL | 1 + .../examples/component_preview.rs | 18 +++ .../src}/component_preview.rs | 14 +- .../src/component_preview_example.rs | 145 ++++++++++++++++++ .../src}/persistence.rs | 0 crates/zed/Cargo.toml | 2 +- crates/zed/src/main.rs | 2 +- crates/zed/src/zed.rs | 1 - 11 files changed, 248 insertions(+), 11 deletions(-) create mode 100644 crates/component_preview/Cargo.toml create mode 120000 crates/component_preview/LICENSE-GPL create mode 100644 crates/component_preview/examples/component_preview.rs rename crates/{zed/src/zed => component_preview/src}/component_preview.rs (99%) create mode 100644 crates/component_preview/src/component_preview_example.rs rename crates/{zed/src/zed/component_preview => component_preview/src}/persistence.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index f9acd6989be8734b6c5b528435fccea62d10f027..f12d6a3484907a873e0e02d8e7af333c31dd9740 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3525,6 +3525,33 @@ dependencies = [ "theme", ] +[[package]] +name = "component_preview" +version = "0.1.0" +dependencies = [ + "anyhow", + "client", + "collections", + "component", + "db", + "fs", + "gpui", + "language", + "log", + "node_runtime", + "notifications", + "project", + "release_channel", + "reqwest_client", + "session", + "settings", + "theme", + "ui", + "ui_input", + "uuid", + "workspace", +] + [[package]] name = "compression-codecs" version = "0.4.31" @@ -20643,6 +20670,7 @@ dependencies = [ "collections", "command_palette", "component", + "component_preview", "copilot", "crashes", "dap", @@ -20748,7 +20776,6 @@ dependencies = [ "tree-sitter-md", "tree-sitter-rust", "ui", - "ui_input", "ui_prompt", "url", "urlencoding", diff --git a/Cargo.toml b/Cargo.toml index b507e8824484ea670619b5225fef9cfd41c81d4c..54f256abac03c50d5aa0ca0d1c5dd7d433319ddf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ members = [ "crates/command_palette", "crates/command_palette_hooks", "crates/component", + "crates/component_preview", "crates/context_server", "crates/copilot", "crates/crashes", @@ -275,6 +276,7 @@ collections = { path = "crates/collections", version = "0.1.0" } command_palette = { path = "crates/command_palette" } command_palette_hooks = { path = "crates/command_palette_hooks" } component = { path = "crates/component" } +component_preview = { path = "crates/component_preview" } context_server = { path = "crates/context_server" } copilot = { path = "crates/copilot" } crashes = { path = "crates/crashes" } diff --git a/crates/component_preview/Cargo.toml b/crates/component_preview/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..d7ca3bad47d74d86c701007da879ddf092a08b73 --- /dev/null +++ b/crates/component_preview/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "component_preview" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "GPL-3.0-or-later" + +[lints] +workspace = true + +[lib] +path = "src/component_preview.rs" + +[features] +default = [] +preview = [] +test-support = ["db/test-support"] + +[dependencies] +anyhow.workspace = true +client.workspace = true +collections.workspace = true +component.workspace = true +db.workspace = true +fs.workspace = true +gpui.workspace = true +language.workspace = true +log.workspace = true +node_runtime.workspace = true +notifications.workspace = true +project.workspace = true +release_channel.workspace = true +reqwest_client.workspace = true +session.workspace = true +settings.workspace = true +theme.workspace = true +ui.workspace = true +ui_input.workspace = true +uuid.workspace = true +workspace.workspace = true + +[[example]] +name = "component_preview" +path = "examples/component_preview.rs" +required-features = ["preview"] diff --git a/crates/component_preview/LICENSE-GPL b/crates/component_preview/LICENSE-GPL new file mode 120000 index 0000000000000000000000000000000000000000..e0f9dbd5d63fef1630c297edc4ceba4790be6f02 --- /dev/null +++ b/crates/component_preview/LICENSE-GPL @@ -0,0 +1 @@ +LICENSE-GPL \ No newline at end of file diff --git a/crates/component_preview/examples/component_preview.rs b/crates/component_preview/examples/component_preview.rs new file mode 100644 index 0000000000000000000000000000000000000000..a49110e91ee76fef8b6f69048153f47493e52097 --- /dev/null +++ b/crates/component_preview/examples/component_preview.rs @@ -0,0 +1,18 @@ +//! Component Preview Example +//! +//! Run with: `cargo run -p component_preview --example component_preview --features="preview"` +//! +//! To use this in other projects, add the following to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! component_preview = { path = "../component_preview", features = ["preview"] } +//! +//! [[example]] +//! name = "component_preview" +//! path = "examples/component_preview.rs" +//! ``` + +fn main() { + component_preview::run_component_preview(); +} diff --git a/crates/zed/src/zed/component_preview.rs b/crates/component_preview/src/component_preview.rs similarity index 99% rename from crates/zed/src/zed/component_preview.rs rename to crates/component_preview/src/component_preview.rs index e3c7fc8df542448d5b8b290e96405546be7b4b1e..0f4a8d94baf9021f0d6911e693a435ee4ab5e524 100644 --- a/crates/zed/src/zed/component_preview.rs +++ b/crates/component_preview/src/component_preview.rs @@ -1,7 +1,4 @@ -//! # Component Preview -//! -//! A view for exploring Zed components. - +mod component_preview_example; mod persistence; use client::UserStore; @@ -11,18 +8,21 @@ use gpui::{ App, Entity, EventEmitter, FocusHandle, Focusable, Task, WeakEntity, Window, list, prelude::*, }; use gpui::{ListState, ScrollHandle, ScrollStrategy, UniformListScrollHandle}; -use languages::LanguageRegistry; +use language::LanguageRegistry; use notifications::status_toast::{StatusToast, ToastIcon}; use persistence::COMPONENT_PREVIEW_DB; use project::Project; use std::{iter::Iterator, ops::Range, sync::Arc}; use ui::{ButtonLike, Divider, HighlightedLabel, ListItem, ListSubHeader, Tooltip, prelude::*}; use ui_input::InputField; +use workspace::AppState; use workspace::{ - AppState, Item, ItemId, SerializableItem, Workspace, WorkspaceId, delete_unloaded_items, - item::ItemEvent, + Item, ItemId, SerializableItem, Workspace, WorkspaceId, delete_unloaded_items, item::ItemEvent, }; +#[allow(unused_imports)] +pub use component_preview_example::*; + pub fn init(app_state: Arc, cx: &mut App) { workspace::register_serializable_item::(cx); diff --git a/crates/component_preview/src/component_preview_example.rs b/crates/component_preview/src/component_preview_example.rs new file mode 100644 index 0000000000000000000000000000000000000000..a5efd015566a6bafdf333346c33810032ec08284 --- /dev/null +++ b/crates/component_preview/src/component_preview_example.rs @@ -0,0 +1,145 @@ +/// Run the component preview application. +/// +/// This initializes the application with minimal required infrastructure +/// and opens a workspace with the ComponentPreview item. +#[cfg(feature = "preview")] +pub fn run_component_preview() { + use fs::RealFs; + use gpui::{ + AppContext as _, Application, Bounds, KeyBinding, WindowBounds, WindowOptions, actions, + size, + }; + + use client::{Client, UserStore}; + use language::LanguageRegistry; + use node_runtime::NodeRuntime; + use project::Project; + use reqwest_client::ReqwestClient; + use session::{AppSession, Session}; + use std::sync::Arc; + use ui::{App, px}; + use workspace::{AppState, Workspace, WorkspaceStore}; + + use crate::{ComponentPreview, init}; + + actions!(zed, [Quit]); + + fn quit(_: &Quit, cx: &mut App) { + cx.quit(); + } + + Application::new().run(|cx| { + component::init(); + + cx.on_action(quit); + cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]); + let version = release_channel::AppVersion::load(env!("CARGO_PKG_VERSION"), None, None); + release_channel::init(version, cx); + + let http_client = + ReqwestClient::user_agent("component_preview").expect("Failed to create HTTP client"); + cx.set_http_client(Arc::new(http_client)); + + let fs = Arc::new(RealFs::new(None, cx.background_executor().clone())); + ::set_global(fs.clone(), cx); + + settings::init(cx); + theme::init(theme::LoadThemes::JustBase, cx); + + let languages = Arc::new(LanguageRegistry::new(cx.background_executor().clone())); + let client = Client::production(cx); + client::init(&client, cx); + + let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); + let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx)); + let session_id = uuid::Uuid::new_v4().to_string(); + let session = cx.background_executor().block(Session::new(session_id)); + let session = cx.new(|cx| AppSession::new(session, cx)); + let node_runtime = NodeRuntime::unavailable(); + + let app_state = Arc::new(AppState { + languages, + client, + user_store, + workspace_store, + fs, + build_window_options: |_, _| Default::default(), + node_runtime, + session, + }); + AppState::set_global(Arc::downgrade(&app_state), cx); + + workspace::init(app_state.clone(), cx); + init(app_state.clone(), cx); + + let size = size(px(1200.), px(800.)); + let bounds = Bounds::centered(None, size, cx); + + cx.open_window( + WindowOptions { + window_bounds: Some(WindowBounds::Windowed(bounds)), + ..Default::default() + }, + { + move |window, cx| { + let app_state = app_state; + theme::setup_ui_font(window, cx); + + let project = Project::local( + app_state.client.clone(), + app_state.node_runtime.clone(), + app_state.user_store.clone(), + app_state.languages.clone(), + app_state.fs.clone(), + None, + false, + cx, + ); + + let workspace = cx.new(|cx| { + Workspace::new( + Default::default(), + project.clone(), + app_state.clone(), + window, + cx, + ) + }); + + workspace.update(cx, |workspace, cx| { + let weak_workspace = cx.entity().downgrade(); + let language_registry = app_state.languages.clone(); + let user_store = app_state.user_store.clone(); + + let component_preview = cx.new(|cx| { + ComponentPreview::new( + weak_workspace, + project, + language_registry, + user_store, + None, + None, + window, + cx, + ) + .expect("Failed to create component preview") + }); + + workspace.add_item_to_active_pane( + Box::new(component_preview), + None, + true, + window, + cx, + ); + }); + + workspace + } + }, + ) + .expect("Failed to open component preview window"); + + cx.activate(true); + }); +} diff --git a/crates/zed/src/zed/component_preview/persistence.rs b/crates/component_preview/src/persistence.rs similarity index 100% rename from crates/zed/src/zed/component_preview/persistence.rs rename to crates/component_preview/src/persistence.rs diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 80eca20e00309bb8d22552287a1c39cb9891307d..5c5d35944672a36733d6da50505f8d5bacad74f3 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -41,6 +41,7 @@ collab_ui.workspace = true collections.workspace = true command_palette.workspace = true component.workspace = true +component_preview.workspace = true copilot.workspace = true crashes.workspace = true dap_adapters.workspace = true @@ -148,7 +149,6 @@ ztracing.workspace = true tracing.workspace = true toolchain_selector.workspace = true ui.workspace = true -ui_input.workspace = true ui_prompt.workspace = true url.workspace = true urlencoding.workspace = true diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 03e02bb0107d736c07eb3fc9626856943f8d80a6..bdf3bf3f950a329e7c1b49f5ce27560b00807a5f 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -774,7 +774,7 @@ fn main() { let app_state = app_state.clone(); - crate::zed::component_preview::init(app_state.clone(), cx); + component_preview::init(app_state.clone(), cx); cx.spawn(async move |cx| { while let Some(urls) = open_rx.next().await { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 3441cb88d96b06dfdbb65a58553d2c58f435d157..392a57520d28be021e55cbd890d2eb968370c2f7 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1,5 +1,4 @@ mod app_menus; -pub mod component_preview; pub mod edit_prediction_registry; #[cfg(target_os = "macos")] pub(crate) mod mac_only_instance;