diff --git a/Cargo.lock b/Cargo.lock index ea4070305367ca766c3ee889ab9f358daa4fbc68..1579f5608183850f3fe4bc2cf2b916940ba3d38f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -433,32 +433,6 @@ dependencies = [ "zed_actions", ] -[[package]] -name = "agent_ui_v2" -version = "0.1.0" -dependencies = [ - "acp_thread", - "agent", - "agent-client-protocol", - "agent_servers", - "agent_settings", - "agent_ui", - "anyhow", - "db", - "feature_flags", - "fs", - "gpui", - "log", - "project", - "prompt_store", - "serde", - "serde_json", - "settings", - "ui", - "util", - "workspace", -] - [[package]] name = "ahash" version = "0.7.8" @@ -21047,7 +21021,6 @@ dependencies = [ "agent_servers", "agent_settings", "agent_ui", - "agent_ui_v2", "anyhow", "ashpd", "askpass", diff --git a/Cargo.toml b/Cargo.toml index 3ae1b149b3e0f26bf6ed91ae4cda8482ff1bea58..586a7ce0331785fddf11ecab11fcdb2ef2952e5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ members = [ "crates/agent_servers", "crates/agent_settings", "crates/agent_ui", - "crates/agent_ui_v2", "crates/ai_onboarding", "crates/anthropic", "crates/askpass", @@ -255,7 +254,6 @@ action_log = { path = "crates/action_log" } agent = { path = "crates/agent" } activity_indicator = { path = "crates/activity_indicator" } agent_ui = { path = "crates/agent_ui" } -agent_ui_v2 = { path = "crates/agent_ui_v2" } agent_settings = { path = "crates/agent_settings" } agent_servers = { path = "crates/agent_servers" } ai_onboarding = { path = "crates/ai_onboarding" } diff --git a/assets/settings/default.json b/assets/settings/default.json index 19a149a84fd9b5dfae7305c6527147b2561a8512..3e6282e14eaebfb5a1d091a90c1883ed84da3d92 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -931,8 +931,6 @@ "button": true, // Where to dock the agent panel. Can be 'left', 'right' or 'bottom'. "dock": "right", - // Where to dock the agents panel. Can be 'left' or 'right'. - "agents_panel_dock": "left", // Default width when the agent panel is docked to the left or right. "default_width": 640, // Default height when the agent panel is docked to the bottom. diff --git a/crates/agent/src/tool_permissions.rs b/crates/agent/src/tool_permissions.rs index efafe917d8cca94fd78b4f3cbdd9fb505ab6ab8f..ef6e699d407eb9d7fbd53f9cdb8b8e46a2ed3b3e 100644 --- a/crates/agent/src/tool_permissions.rs +++ b/crates/agent/src/tool_permissions.rs @@ -528,7 +528,7 @@ mod tests { use crate::tools::{DeletePathTool, EditFileTool, FetchTool, TerminalTool}; use agent_settings::{AgentProfileId, CompiledRegex, InvalidRegexPattern, ToolRules}; use gpui::px; - use settings::{DefaultAgentView, DockPosition, DockSide, NotifyWhenAgentWaiting}; + use settings::{DefaultAgentView, DockPosition, NotifyWhenAgentWaiting}; use std::sync::Arc; fn test_agent_settings(tool_permissions: ToolPermissions) -> AgentSettings { @@ -536,7 +536,6 @@ mod tests { enabled: true, button: true, dock: DockPosition::Right, - agents_panel_dock: DockSide::Left, default_width: px(300.), default_height: px(600.), default_model: None, diff --git a/crates/agent_settings/src/agent_settings.rs b/crates/agent_settings/src/agent_settings.rs index fffb55c34fa1c38a4366052ebc0383e7e3d5a2ea..02341af42b9247ba07cb3f8c771a51626cd721ed 100644 --- a/crates/agent_settings/src/agent_settings.rs +++ b/crates/agent_settings/src/agent_settings.rs @@ -11,7 +11,7 @@ use project::DisableAiSettings; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{ - DefaultAgentView, DockPosition, DockSide, LanguageModelParameters, LanguageModelSelection, + DefaultAgentView, DockPosition, LanguageModelParameters, LanguageModelSelection, NotifyWhenAgentWaiting, RegisterSetting, Settings, ToolPermissionMode, }; @@ -26,7 +26,6 @@ pub struct AgentSettings { pub enabled: bool, pub button: bool, pub dock: DockPosition, - pub agents_panel_dock: DockSide, pub default_width: Pixels, pub default_height: Pixels, pub default_model: Option, @@ -407,7 +406,6 @@ impl Settings for AgentSettings { enabled: agent.enabled.unwrap(), button: agent.button.unwrap(), dock: agent.dock.unwrap(), - agents_panel_dock: agent.agents_panel_dock.unwrap(), default_width: px(agent.default_width.unwrap()), default_height: px(agent.default_height.unwrap()), default_model: Some(agent.default_model.unwrap()), diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index 112e94567f3c3c974d43374d1392b510ed3e0e46..8a0d26bcf0429c9ea42c74b0e14c547e7ddf15a2 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -431,9 +431,6 @@ fn update_command_palette_filter(cx: &mut App) { filter.show_namespace("zed_predict_onboarding"); filter.show_action_types(&[TypeId::of::()]); - if !agent_v2_enabled { - filter.hide_action_types(&[TypeId::of::()]); - } } if agent_v2_enabled { @@ -539,7 +536,7 @@ mod tests { use gpui::{BorrowAppContext, TestAppContext, px}; use project::DisableAiSettings; use settings::{ - DefaultAgentView, DockPosition, DockSide, NotifyWhenAgentWaiting, Settings, SettingsStore, + DefaultAgentView, DockPosition, NotifyWhenAgentWaiting, Settings, SettingsStore, }; #[gpui::test] @@ -558,7 +555,6 @@ mod tests { enabled: true, button: true, dock: DockPosition::Right, - agents_panel_dock: DockSide::Left, default_width: px(300.), default_height: px(600.), default_model: None, diff --git a/crates/agent_ui_v2/Cargo.toml b/crates/agent_ui_v2/Cargo.toml deleted file mode 100644 index 368fb8f271ab0ae4272b5c674c1a412fabeb77d4..0000000000000000000000000000000000000000 --- a/crates/agent_ui_v2/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = "agent_ui_v2" -version = "0.1.0" -edition.workspace = true -publish.workspace = true -license = "GPL-3.0-or-later" - -[lints] -workspace = true - -[lib] -path = "src/agent_ui_v2.rs" -doctest = false - -[features] -test-support = ["agent/test-support"] - - -[dependencies] -agent.workspace = true -acp_thread.workspace = true -agent-client-protocol.workspace = true -agent_servers.workspace = true -agent_settings.workspace = true -agent_ui.workspace = true -anyhow.workspace = true -db.workspace = true -feature_flags.workspace = true -fs.workspace = true -gpui.workspace = true -log.workspace = true -project.workspace = true -prompt_store.workspace = true -serde.workspace = true -serde_json.workspace = true -settings.workspace = true -ui.workspace = true -util.workspace = true -workspace.workspace = true - -[dev-dependencies] -agent = { workspace = true, features = ["test-support"] } diff --git a/crates/agent_ui_v2/LICENSE-GPL b/crates/agent_ui_v2/LICENSE-GPL deleted file mode 120000 index 89e542f750cd3860a0598eff0dc34b56d7336dc4..0000000000000000000000000000000000000000 --- a/crates/agent_ui_v2/LICENSE-GPL +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE-GPL \ No newline at end of file diff --git a/crates/agent_ui_v2/src/agent_thread_pane.rs b/crates/agent_ui_v2/src/agent_thread_pane.rs deleted file mode 100644 index c6ae3f0ca525b2df5810a8b11c65438428d05a3f..0000000000000000000000000000000000000000 --- a/crates/agent_ui_v2/src/agent_thread_pane.rs +++ /dev/null @@ -1,284 +0,0 @@ -use acp_thread::AgentSessionInfo; -use agent::{NativeAgentServer, ThreadStore}; -use agent_client_protocol as acp; -use agent_servers::AgentServer; -use agent_settings::AgentSettings; -use agent_ui::acp::{AcpServerView, AcpThreadHistory}; -use fs::Fs; -use gpui::{ - Entity, EventEmitter, Focusable, Pixels, SharedString, Subscription, WeakEntity, prelude::*, -}; -use project::Project; -use prompt_store::PromptStore; -use serde::{Deserialize, Serialize}; -use settings::DockSide; -use settings::Settings as _; -use std::rc::Rc; -use std::sync::Arc; -use ui::{Tab, Tooltip, prelude::*}; -use workspace::{ - Workspace, - dock::{ClosePane, MinimizePane, UtilityPane, UtilityPanePosition}, - utility_pane::UtilityPaneSlot, -}; - -pub const DEFAULT_UTILITY_PANE_WIDTH: Pixels = gpui::px(400.0); - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum SerializedHistoryEntryId { - AcpThread(String), -} - -impl From for SerializedHistoryEntryId { - fn from(id: acp::SessionId) -> Self { - SerializedHistoryEntryId::AcpThread(id.0.to_string()) - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct SerializedAgentThreadPane { - pub expanded: bool, - pub width: Option, - pub thread_id: Option, -} - -pub enum AgentsUtilityPaneEvent { - StateChanged, -} - -impl EventEmitter for AgentThreadPane {} -impl EventEmitter for AgentThreadPane {} -impl EventEmitter for AgentThreadPane {} - -struct ActiveThreadView { - view: Entity, - thread_id: acp::SessionId, - _notify: Subscription, -} - -pub struct AgentThreadPane { - focus_handle: gpui::FocusHandle, - expanded: bool, - width: Option, - thread_view: Option, - workspace: WeakEntity, - history: Entity, -} - -impl AgentThreadPane { - pub fn new( - workspace: WeakEntity, - history: Entity, - cx: &mut ui::Context, - ) -> Self { - let focus_handle = cx.focus_handle(); - Self { - focus_handle, - expanded: false, - width: None, - thread_view: None, - workspace, - history, - } - } - - pub fn thread_id(&self) -> Option { - self.thread_view.as_ref().map(|tv| tv.thread_id.clone()) - } - - pub fn serialize(&self) -> SerializedAgentThreadPane { - SerializedAgentThreadPane { - expanded: self.expanded, - width: self.width, - thread_id: self.thread_id().map(SerializedHistoryEntryId::from), - } - } - - pub fn open_thread( - &mut self, - entry: AgentSessionInfo, - fs: Arc, - workspace: WeakEntity, - project: Entity, - thread_store: Entity, - prompt_store: Option>, - window: &mut Window, - cx: &mut Context, - ) { - let thread_id = entry.session_id.clone(); - let resume_thread = Some(entry); - - let agent: Rc = Rc::new(NativeAgentServer::new(fs, thread_store.clone())); - - let history = self.history.clone(); - let thread_view = cx.new(|cx| { - AcpServerView::new( - agent, - resume_thread, - None, - workspace, - project, - Some(thread_store), - prompt_store, - history, - window, - cx, - ) - }); - - let notify = cx.observe(&thread_view, |_, _, cx| { - cx.notify(); - }); - - self.thread_view = Some(ActiveThreadView { - view: thread_view, - thread_id, - _notify: notify, - }); - - cx.notify(); - } - - fn title(&self, cx: &App) -> SharedString { - if let Some(active_thread_view) = &self.thread_view { - let thread_view = active_thread_view.view.read(cx); - if let Some(ready) = thread_view.active_thread() { - let title = ready.read(cx).thread.read(cx).title(); - if !title.is_empty() { - return title; - } - } - thread_view.title(cx) - } else { - "Thread".into() - } - } - - fn render_header(&self, window: &mut Window, cx: &mut Context) -> impl IntoElement { - let position = self.position(window, cx); - let slot = match position { - UtilityPanePosition::Left => UtilityPaneSlot::Left, - UtilityPanePosition::Right => UtilityPaneSlot::Right, - }; - - let workspace = self.workspace.clone(); - let toggle_icon = self.toggle_icon(cx); - let title = self.title(cx); - - let pane_toggle_button = |workspace: WeakEntity| { - IconButton::new("toggle_utility_pane", toggle_icon) - .icon_size(IconSize::Small) - .tooltip(Tooltip::text("Toggle Agent Pane")) - .on_click(move |_, window, cx| { - workspace - .update(cx, |workspace, cx| { - workspace.toggle_utility_pane(slot, window, cx) - }) - .ok(); - }) - }; - - h_flex() - .id("utility-pane-header") - .w_full() - .h(Tab::container_height(cx)) - .px_1p5() - .gap(DynamicSpacing::Base06.rems(cx)) - .when(slot == UtilityPaneSlot::Right, |this| { - this.flex_row_reverse() - }) - .flex_none() - .border_b_1() - .border_color(cx.theme().colors().border) - .child(pane_toggle_button(workspace)) - .child( - h_flex() - .size_full() - .min_w_0() - .gap_1() - .map(|this| { - if slot == UtilityPaneSlot::Right { - this.flex_row_reverse().justify_start() - } else { - this.justify_between() - } - }) - .child(Label::new(title).truncate()) - .child( - IconButton::new("close_btn", IconName::Close) - .icon_size(IconSize::Small) - .tooltip(Tooltip::text("Close Agent Pane")) - .on_click(cx.listener(|this, _: &gpui::ClickEvent, _window, cx| { - cx.emit(ClosePane); - this.thread_view = None; - cx.notify() - })), - ), - ) - } -} - -impl Focusable for AgentThreadPane { - fn focus_handle(&self, cx: &ui::App) -> gpui::FocusHandle { - if let Some(thread_view) = &self.thread_view { - thread_view.view.focus_handle(cx) - } else { - self.focus_handle.clone() - } - } -} - -impl UtilityPane for AgentThreadPane { - fn position(&self, _window: &Window, cx: &App) -> UtilityPanePosition { - match AgentSettings::get_global(cx).agents_panel_dock { - DockSide::Left => UtilityPanePosition::Left, - DockSide::Right => UtilityPanePosition::Right, - } - } - - fn toggle_icon(&self, _cx: &App) -> IconName { - IconName::Thread - } - - fn expanded(&self, _cx: &App) -> bool { - self.expanded - } - - fn set_expanded(&mut self, expanded: bool, cx: &mut Context) { - self.expanded = expanded; - cx.emit(AgentsUtilityPaneEvent::StateChanged); - cx.notify(); - } - - fn width(&self, _cx: &App) -> Pixels { - self.width.unwrap_or(DEFAULT_UTILITY_PANE_WIDTH) - } - - fn set_width(&mut self, width: Option, cx: &mut Context) { - self.width = width; - cx.emit(AgentsUtilityPaneEvent::StateChanged); - cx.notify(); - } -} - -impl Render for AgentThreadPane { - fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { - let content = if let Some(thread_view) = &self.thread_view { - div().size_full().child(thread_view.view.clone()) - } else { - div() - .size_full() - .flex() - .items_center() - .justify_center() - .child(Label::new("Select a thread to view details").size(LabelSize::Default)) - }; - - div() - .size_full() - .flex() - .flex_col() - .child(self.render_header(window, cx)) - .child(content) - } -} diff --git a/crates/agent_ui_v2/src/agent_ui_v2.rs b/crates/agent_ui_v2/src/agent_ui_v2.rs deleted file mode 100644 index eb91b44f2524983fc27fb976ac1ef05ae356ae13..0000000000000000000000000000000000000000 --- a/crates/agent_ui_v2/src/agent_ui_v2.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod agent_thread_pane; - -pub mod agents_panel; diff --git a/crates/agent_ui_v2/src/agents_panel.rs b/crates/agent_ui_v2/src/agents_panel.rs deleted file mode 100644 index 3f56704850b5cad0d3af349ad92efe8698a923ef..0000000000000000000000000000000000000000 --- a/crates/agent_ui_v2/src/agents_panel.rs +++ /dev/null @@ -1,481 +0,0 @@ -use acp_thread::AgentSessionInfo; -use agent::{NativeAgentServer, ThreadStore}; -use agent_client_protocol as acp; -use agent_servers::{AgentServer, AgentServerDelegate}; -use agent_settings::AgentSettings; -use anyhow::Result; -use db::kvp::KEY_VALUE_STORE; -use feature_flags::{AgentV2FeatureFlag, FeatureFlagAppExt}; -use fs::Fs; -use gpui::{ - Action, AsyncWindowContext, Entity, EventEmitter, Focusable, Pixels, Subscription, Task, - WeakEntity, actions, prelude::*, -}; -use project::Project; -use prompt_store::PromptStore; -use serde::{Deserialize, Serialize}; -use settings::{Settings as _, update_settings_file}; -use std::sync::Arc; -use ui::{App, Context, IconName, IntoElement, ParentElement, Render, Styled, Window}; -use util::ResultExt; -use workspace::{ - Panel, Workspace, - dock::{ClosePane, DockPosition, PanelEvent, UtilityPane}, - utility_pane::{UtilityPaneSlot, utility_slot_for_dock_position}, -}; - -use crate::agent_thread_pane::{ - AgentThreadPane, AgentsUtilityPaneEvent, SerializedAgentThreadPane, SerializedHistoryEntryId, -}; -use agent_ui::acp::{AcpThreadHistory, ThreadHistoryEvent}; - -const AGENTS_PANEL_KEY: &str = "agents_panel"; - -#[derive(Serialize, Deserialize, Debug)] -struct SerializedAgentsPanel { - width: Option, - pane: Option, -} - -actions!( - agents, - [ - /// Toggle the visibility of the agents panel. - ToggleAgentsPanel - ] -); - -pub fn init(cx: &mut App) { - cx.observe_new(|workspace: &mut Workspace, _, _| { - workspace.register_action(|workspace, _: &ToggleAgentsPanel, window, cx| { - workspace.toggle_panel_focus::(window, cx); - }); - }) - .detach(); -} - -pub struct AgentsPanel { - focus_handle: gpui::FocusHandle, - workspace: WeakEntity, - project: Entity, - agent_thread_pane: Option>, - history: Entity, - thread_store: Entity, - prompt_store: Option>, - fs: Arc, - width: Option, - pending_restore: Option, - pending_serialization: Task>, - _subscriptions: Vec, -} - -impl AgentsPanel { - pub fn load( - workspace: WeakEntity, - cx: AsyncWindowContext, - ) -> Task, anyhow::Error>> { - cx.spawn(async move |cx| { - let serialized_panel = cx - .background_spawn(async move { - KEY_VALUE_STORE - .read_kvp(AGENTS_PANEL_KEY) - .ok() - .flatten() - .and_then(|panel| { - serde_json::from_str::(&panel).ok() - }) - }) - .await; - - let (fs, project) = workspace.update(cx, |workspace, _| { - let fs = workspace.app_state().fs.clone(); - let project = workspace.project().clone(); - (fs, project) - })?; - - let prompt_store = workspace - .update(cx, |_, cx| PromptStore::global(cx))? - .await - .log_err(); - - workspace.update_in(cx, |_, window, cx| { - cx.new(|cx| { - let mut panel = - Self::new(workspace.clone(), fs, project, prompt_store, window, cx); - if let Some(serialized_panel) = serialized_panel { - panel.width = serialized_panel.width; - if let Some(serialized_pane) = serialized_panel.pane { - panel.restore_utility_pane(serialized_pane, window, cx); - } - } - panel - }) - }) - }) - } - - fn new( - workspace: WeakEntity, - fs: Arc, - project: Entity, - prompt_store: Option>, - window: &mut Window, - cx: &mut ui::Context, - ) -> Self { - let focus_handle = cx.focus_handle(); - - let thread_store = ThreadStore::global(cx); - let history = cx.new(|cx| AcpThreadHistory::new(None, window, cx)); - - let history_handle = history.clone(); - let connect_project = project.clone(); - let connect_thread_store = thread_store.clone(); - let connect_fs = fs.clone(); - cx.spawn(async move |_, cx| { - let connect_task = cx.update(|cx| { - let delegate = AgentServerDelegate::new( - connect_project.read(cx).agent_server_store().clone(), - connect_project.clone(), - None, - None, - ); - let server = NativeAgentServer::new(connect_fs, connect_thread_store); - server.connect(None, delegate, cx) - }); - let connection = match connect_task.await { - Ok((connection, _)) => connection, - Err(error) => { - log::error!("Failed to connect native agent for history: {error:#}"); - return; - } - }; - - cx.update(|cx| { - if connection.supports_session_history(cx) - && let Some(session_list) = connection.session_list(cx) - { - history_handle.update(cx, |history, cx| { - history.set_session_list(Some(session_list), cx); - }); - } - }); - }) - .detach(); - - let this = cx.weak_entity(); - let subscriptions = vec![ - cx.subscribe_in(&history, window, Self::handle_history_event), - cx.observe_in(&history, window, Self::handle_history_updated), - cx.on_flags_ready(move |_, cx| { - this.update(cx, |_, cx| { - cx.notify(); - }) - .ok(); - }), - ]; - - Self { - focus_handle, - workspace, - project, - agent_thread_pane: None, - history, - thread_store, - prompt_store, - fs, - width: None, - pending_restore: None, - pending_serialization: Task::ready(None), - _subscriptions: subscriptions, - } - } - - fn restore_utility_pane( - &mut self, - serialized_pane: SerializedAgentThreadPane, - window: &mut Window, - cx: &mut Context, - ) { - let Some(thread_id) = &serialized_pane.thread_id else { - return; - }; - - let SerializedHistoryEntryId::AcpThread(id) = thread_id; - let session_id = acp::SessionId::new(id.clone()); - if let Some(entry) = self.history.read(cx).session_for_id(&session_id) { - self.open_thread( - entry, - serialized_pane.expanded, - serialized_pane.width, - window, - cx, - ); - } else { - self.pending_restore = Some(serialized_pane); - } - } - - fn handle_utility_pane_event( - &mut self, - _utility_pane: Entity, - event: &AgentsUtilityPaneEvent, - cx: &mut Context, - ) { - match event { - AgentsUtilityPaneEvent::StateChanged => { - self.serialize(cx); - cx.notify(); - } - } - } - - fn handle_close_pane_event( - &mut self, - _utility_pane: Entity, - _event: &ClosePane, - cx: &mut Context, - ) { - self.agent_thread_pane = None; - self.serialize(cx); - cx.notify(); - } - - fn handle_history_updated( - &mut self, - _history: Entity, - window: &mut Window, - cx: &mut Context, - ) { - self.maybe_restore_pending(window, cx); - } - - fn handle_history_event( - &mut self, - _history: &Entity, - event: &ThreadHistoryEvent, - window: &mut Window, - cx: &mut Context, - ) { - match event { - ThreadHistoryEvent::Open(entry) => { - self.open_thread(entry.clone(), true, None, window, cx); - } - } - } - - fn maybe_restore_pending(&mut self, window: &mut Window, cx: &mut Context) { - if self.agent_thread_pane.is_some() { - self.pending_restore = None; - return; - } - - let Some(pending) = self.pending_restore.as_ref() else { - return; - }; - let Some(thread_id) = &pending.thread_id else { - self.pending_restore = None; - return; - }; - - let SerializedHistoryEntryId::AcpThread(id) = thread_id; - let session_id = acp::SessionId::new(id.clone()); - let Some(entry) = self.history.read(cx).session_for_id(&session_id) else { - return; - }; - - let pending = self.pending_restore.take().expect("pending restore"); - self.open_thread(entry, pending.expanded, pending.width, window, cx); - } - - fn open_thread( - &mut self, - entry: AgentSessionInfo, - expanded: bool, - width: Option, - window: &mut Window, - cx: &mut Context, - ) { - let entry_id = entry.session_id.clone(); - self.pending_restore = None; - - if let Some(existing_pane) = &self.agent_thread_pane { - if existing_pane.read(cx).thread_id() == Some(entry_id) { - existing_pane.update(cx, |pane, cx| { - pane.set_expanded(true, cx); - }); - return; - } - } - - let fs = self.fs.clone(); - let workspace = self.workspace.clone(); - let project = self.project.clone(); - let thread_store = self.thread_store.clone(); - let prompt_store = self.prompt_store.clone(); - let history = self.history.clone(); - - let agent_thread_pane = cx.new(|cx| { - let mut pane = AgentThreadPane::new(workspace.clone(), history, cx); - pane.open_thread( - entry, - fs, - workspace.clone(), - project, - thread_store, - prompt_store, - window, - cx, - ); - if let Some(width) = width { - pane.set_width(Some(width), cx); - } - pane.set_expanded(expanded, cx); - pane - }); - - let state_subscription = cx.subscribe(&agent_thread_pane, Self::handle_utility_pane_event); - let close_subscription = cx.subscribe(&agent_thread_pane, Self::handle_close_pane_event); - - self._subscriptions.push(state_subscription); - self._subscriptions.push(close_subscription); - - let slot = self.utility_slot(window, cx); - let panel_id = cx.entity_id(); - - if let Some(workspace) = self.workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - workspace.register_utility_pane(slot, panel_id, agent_thread_pane.clone(), cx); - }); - } - - self.agent_thread_pane = Some(agent_thread_pane); - self.serialize(cx); - cx.notify(); - } - - fn utility_slot(&self, window: &Window, cx: &App) -> UtilityPaneSlot { - let position = self.position(window, cx); - utility_slot_for_dock_position(position) - } - - fn re_register_utility_pane(&mut self, window: &mut Window, cx: &mut Context) { - if let Some(pane) = &self.agent_thread_pane { - let slot = self.utility_slot(window, cx); - let panel_id = cx.entity_id(); - let pane = pane.clone(); - - if let Some(workspace) = self.workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - workspace.register_utility_pane(slot, panel_id, pane, cx); - }); - } - } - } - - fn serialize(&mut self, cx: &mut Context) { - let width = self.width; - let pane = self - .agent_thread_pane - .as_ref() - .map(|pane| pane.read(cx).serialize()); - - self.pending_serialization = cx.background_spawn(async move { - KEY_VALUE_STORE - .write_kvp( - AGENTS_PANEL_KEY.into(), - serde_json::to_string(&SerializedAgentsPanel { width, pane }).unwrap(), - ) - .await - .log_err() - }); - } -} - -impl EventEmitter for AgentsPanel {} - -impl Focusable for AgentsPanel { - fn focus_handle(&self, _cx: &ui::App) -> gpui::FocusHandle { - self.focus_handle.clone() - } -} - -impl Panel for AgentsPanel { - fn persistent_name() -> &'static str { - "AgentsPanel" - } - - fn panel_key() -> &'static str { - AGENTS_PANEL_KEY - } - - fn position(&self, _window: &Window, cx: &App) -> DockPosition { - match AgentSettings::get_global(cx).agents_panel_dock { - settings::DockSide::Left => DockPosition::Left, - settings::DockSide::Right => DockPosition::Right, - } - } - - fn position_is_valid(&self, position: DockPosition) -> bool { - position != DockPosition::Bottom - } - - fn set_position( - &mut self, - position: DockPosition, - window: &mut Window, - cx: &mut Context, - ) { - update_settings_file(self.fs.clone(), cx, move |settings, _| { - settings.agent.get_or_insert_default().agents_panel_dock = Some(match position { - DockPosition::Left => settings::DockSide::Left, - DockPosition::Right | DockPosition::Bottom => settings::DockSide::Right, - }); - }); - self.re_register_utility_pane(window, cx); - } - - fn size(&self, window: &Window, cx: &App) -> Pixels { - let settings = AgentSettings::get_global(cx); - match self.position(window, cx) { - DockPosition::Left | DockPosition::Right => { - self.width.unwrap_or(settings.default_width) - } - DockPosition::Bottom => self.width.unwrap_or(settings.default_height), - } - } - - fn set_size(&mut self, size: Option, window: &mut Window, cx: &mut Context) { - match self.position(window, cx) { - DockPosition::Left | DockPosition::Right => self.width = size, - DockPosition::Bottom => {} - } - self.serialize(cx); - cx.notify(); - } - - fn icon(&self, _window: &Window, cx: &App) -> Option { - (self.enabled(cx) && AgentSettings::get_global(cx).button).then_some(IconName::ZedAgentTwo) - } - - fn icon_tooltip(&self, _window: &Window, _cx: &App) -> Option<&'static str> { - Some("Agents Panel") - } - - fn toggle_action(&self) -> Box { - Box::new(ToggleAgentsPanel) - } - - fn activation_priority(&self) -> u32 { - 4 - } - - fn enabled(&self, cx: &App) -> bool { - AgentSettings::get_global(cx).enabled(cx) && cx.has_flag::() - } -} - -impl Render for AgentsPanel { - fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { - gpui::div().size_full().child(self.history.clone()) - } -} diff --git a/crates/settings_content/src/agent.rs b/crates/settings_content/src/agent.rs index c592c13c133fe264b254db44250b37dcf520a504..a74c66b10115be548d1ecad53ecd4e3b4a6be48e 100644 --- a/crates/settings_content/src/agent.rs +++ b/crates/settings_content/src/agent.rs @@ -7,7 +7,7 @@ use std::{borrow::Cow, path::PathBuf}; use crate::ExtendingVec; -use crate::{DockPosition, DockSide}; +use crate::DockPosition; #[with_fallible_options] #[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, Default)] @@ -24,10 +24,6 @@ pub struct AgentSettingsContent { /// /// Default: right pub dock: Option, - /// Where to dock the utility pane (the thread view pane). - /// - /// Default: left - pub agents_panel_dock: Option, /// Default width in pixels when the agent panel is docked to the left or right. /// /// Default: 640 diff --git a/crates/ui/src/components/tab_bar.rs b/crates/ui/src/components/tab_bar.rs index 86598b8c6f1ab3a479313c7775405863e9e3b49b..2618d87a46cfef3aa929f01a37311adac8fde9d2 100644 --- a/crates/ui/src/components/tab_bar.rs +++ b/crates/ui/src/components/tab_bar.rs @@ -10,7 +10,6 @@ pub struct TabBar { start_children: SmallVec<[AnyElement; 2]>, children: SmallVec<[AnyElement; 2]>, end_children: SmallVec<[AnyElement; 2]>, - pre_end_children: SmallVec<[AnyElement; 2]>, scroll_handle: Option, } @@ -21,7 +20,6 @@ impl TabBar { start_children: SmallVec::new(), children: SmallVec::new(), end_children: SmallVec::new(), - pre_end_children: SmallVec::new(), scroll_handle: None, } } @@ -72,15 +70,6 @@ impl TabBar { self } - pub fn pre_end_child(mut self, end_child: impl IntoElement) -> Self - where - Self: Sized, - { - self.pre_end_children - .push(end_child.into_element().into_any()); - self - } - pub fn end_children(mut self, end_children: impl IntoIterator) -> Self where Self: Sized, @@ -148,32 +137,17 @@ impl RenderOnce for TabBar { .children(self.children), ), ) - .when( - !self.end_children.is_empty() || !self.pre_end_children.is_empty(), - |this| { - this.child( - h_flex() - .flex_none() - .gap(DynamicSpacing::Base04.rems(cx)) - .px(DynamicSpacing::Base06.rems(cx)) - .children(self.pre_end_children) - .border_color(cx.theme().colors().border) - .border_b_1() - .when(!self.end_children.is_empty(), |div| { - div.child( - h_flex() - .h_full() - .flex_none() - .pl(DynamicSpacing::Base04.rems(cx)) - .gap(DynamicSpacing::Base04.rems(cx)) - .border_l_1() - .border_color(cx.theme().colors().border) - .children(self.end_children), - ) - }), - ) - }, - ) + .when(!self.end_children.is_empty(), |this| { + this.child( + h_flex() + .flex_none() + .gap(DynamicSpacing::Base04.rems(cx)) + .px(DynamicSpacing::Base06.rems(cx)) + .border_color(cx.theme().colors().border) + .border_b_1() + .children(self.end_children), + ) + }) } } diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index b3397dd48f58057a78124b1f6124abbb4eb4087b..439c6df5ee45938368895a67834d57df695fde89 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -27,72 +27,6 @@ pub enum PanelEvent { pub use proto::PanelId; -pub struct MinimizePane; -pub struct ClosePane; - -pub trait UtilityPane: EventEmitter + EventEmitter + Render { - fn position(&self, window: &Window, cx: &App) -> UtilityPanePosition; - /// The icon to render in the adjacent pane's tab bar for toggling this utility pane - fn toggle_icon(&self, cx: &App) -> IconName; - fn expanded(&self, cx: &App) -> bool; - fn set_expanded(&mut self, expanded: bool, cx: &mut Context); - fn width(&self, cx: &App) -> Pixels; - fn set_width(&mut self, width: Option, cx: &mut Context); -} - -pub trait UtilityPaneHandle: 'static + Send + Sync { - fn position(&self, window: &Window, cx: &App) -> UtilityPanePosition; - fn toggle_icon(&self, cx: &App) -> IconName; - fn expanded(&self, cx: &App) -> bool; - fn set_expanded(&self, expanded: bool, cx: &mut App); - fn width(&self, cx: &App) -> Pixels; - fn set_width(&self, width: Option, cx: &mut App); - fn to_any(&self) -> AnyView; - fn box_clone(&self) -> Box; -} - -impl UtilityPaneHandle for Entity -where - T: UtilityPane, -{ - fn position(&self, window: &Window, cx: &App) -> UtilityPanePosition { - self.read(cx).position(window, cx) - } - - fn toggle_icon(&self, cx: &App) -> IconName { - self.read(cx).toggle_icon(cx) - } - - fn expanded(&self, cx: &App) -> bool { - self.read(cx).expanded(cx) - } - - fn set_expanded(&self, expanded: bool, cx: &mut App) { - self.update(cx, |this, cx| this.set_expanded(expanded, cx)) - } - - fn width(&self, cx: &App) -> Pixels { - self.read(cx).width(cx) - } - - fn set_width(&self, width: Option, cx: &mut App) { - self.update(cx, |this, cx| this.set_width(width, cx)) - } - - fn to_any(&self) -> AnyView { - self.clone().into() - } - - fn box_clone(&self) -> Box { - Box::new(self.clone()) - } -} - -pub enum UtilityPanePosition { - Left, - Right, -} - pub trait Panel: Focusable + EventEmitter + Render + Sized { fn persistent_name() -> &'static str; fn panel_key() -> &'static str; diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 252fe90b56435c29306ea9052e491b2f7b8d7dac..eb4b8ea7ea77520d2e45e5c1f1d2e955aa3ae596 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -11,12 +11,10 @@ use crate::{ move_item, notifications::NotifyResultExt, toolbar::Toolbar, - utility_pane::UtilityPaneSlot, workspace_settings::{AutosaveSetting, TabBarSettings, WorkspaceSettings}, }; use anyhow::Result; use collections::{BTreeSet, HashMap, HashSet, VecDeque}; -use feature_flags::{AgentV2FeatureFlag, FeatureFlagAppExt}; use futures::{StreamExt, stream::FuturesUnordered}; use gpui::{ Action, AnyElement, App, AsyncWindowContext, ClickEvent, ClipboardItem, Context, Corner, Div, @@ -425,8 +423,6 @@ pub struct Pane { welcome_page: Option>, pub in_center_group: bool, - pub is_upper_left: bool, - pub is_upper_right: bool, } pub struct ActivationHistoryEntry { @@ -595,8 +591,6 @@ impl Pane { project_item_restoration_data: HashMap::default(), welcome_page: None, in_center_group: false, - is_upper_left: false, - is_upper_right: false, } } @@ -3280,12 +3274,11 @@ impl Pane { } fn render_tab_bar(&mut self, window: &mut Window, cx: &mut Context) -> AnyElement { - let Some(workspace) = self.workspace.upgrade() else { + if self.workspace.upgrade().is_none() { return gpui::Empty.into_any(); - }; + } let focus_handle = self.focus_handle.clone(); - let is_pane_focused = self.has_focus(window, cx); let navigate_backward = IconButton::new("navigate_backward", IconName::ArrowLeft) .icon_size(IconSize::Small) @@ -3310,70 +3303,6 @@ impl Pane { } }); - let open_aside_left = { - let workspace = workspace.read(cx); - workspace.utility_pane(UtilityPaneSlot::Left).map(|pane| { - let toggle_icon = pane.toggle_icon(cx); - let workspace_handle = self.workspace.clone(); - - h_flex() - .h_full() - .pr_1p5() - .border_r_1() - .border_color(cx.theme().colors().border) - .child( - IconButton::new("open_aside_left", toggle_icon) - .icon_size(IconSize::Small) - .tooltip(Tooltip::text("Toggle Agent Pane")) // TODO: Probably want to make this generic - .on_click(move |_, window, cx| { - workspace_handle - .update(cx, |workspace, cx| { - workspace.toggle_utility_pane( - UtilityPaneSlot::Left, - window, - cx, - ) - }) - .ok(); - }), - ) - .into_any_element() - }) - }; - - let open_aside_right = { - let workspace = workspace.read(cx); - workspace.utility_pane(UtilityPaneSlot::Right).map(|pane| { - let toggle_icon = pane.toggle_icon(cx); - let workspace_handle = self.workspace.clone(); - - h_flex() - .h_full() - .when(is_pane_focused, |this| { - this.pl(DynamicSpacing::Base04.rems(cx)) - .border_l_1() - .border_color(cx.theme().colors().border) - }) - .child( - IconButton::new("open_aside_right", toggle_icon) - .icon_size(IconSize::Small) - .tooltip(Tooltip::text("Toggle Agent Pane")) // TODO: Probably want to make this generic - .on_click(move |_, window, cx| { - workspace_handle - .update(cx, |workspace, cx| { - workspace.toggle_utility_pane( - UtilityPaneSlot::Right, - window, - cx, - ) - }) - .ok(); - }), - ) - .into_any_element() - }) - }; - let navigate_forward = IconButton::new("navigate_forward", IconName::ArrowRight) .icon_size(IconSize::Small) .on_click({ @@ -3421,34 +3350,6 @@ impl Pane { let unpinned_tabs = tab_items.split_off(self.pinned_tab_count); let pinned_tabs = tab_items; - let render_aside_toggle_left = cx.has_flag::() - && self - .is_upper_left - .then(|| { - self.workspace.upgrade().and_then(|entity| { - let workspace = entity.read(cx); - workspace - .utility_pane(UtilityPaneSlot::Left) - .map(|pane| !pane.expanded(cx)) - }) - }) - .flatten() - .unwrap_or(false); - - let render_aside_toggle_right = cx.has_flag::() - && self - .is_upper_right - .then(|| { - self.workspace.upgrade().and_then(|entity| { - let workspace = entity.read(cx); - workspace - .utility_pane(UtilityPaneSlot::Right) - .map(|pane| !pane.expanded(cx)) - }) - }) - .flatten() - .unwrap_or(false); - let tab_bar_settings = TabBarSettings::get_global(cx); let use_separate_rows = tab_bar_settings.show_pinned_tabs_in_separate_row; @@ -3459,10 +3360,6 @@ impl Pane { tab_count, navigate_backward, navigate_forward, - open_aside_left, - open_aside_right, - render_aside_toggle_left, - render_aside_toggle_right, window, cx, ) @@ -3473,10 +3370,6 @@ impl Pane { tab_count, navigate_backward, navigate_forward, - open_aside_left, - open_aside_right, - render_aside_toggle_left, - render_aside_toggle_right, window, cx, ) @@ -3488,21 +3381,10 @@ impl Pane { tab_bar: TabBar, navigate_backward: IconButton, navigate_forward: IconButton, - open_aside_left: Option, - render_aside_toggle_left: bool, window: &mut Window, cx: &mut Context, ) -> TabBar { tab_bar - .map(|tab_bar| { - if let Some(open_aside_left) = open_aside_left - && render_aside_toggle_left - { - tab_bar.start_child(open_aside_left) - } else { - tab_bar - } - }) .when( self.display_nav_history_buttons.unwrap_or_default(), |tab_bar| { @@ -3524,22 +3406,6 @@ impl Pane { }) } - fn configure_tab_bar_end( - tab_bar: TabBar, - open_aside_right: Option, - render_aside_toggle_right: bool, - ) -> TabBar { - tab_bar.map(|tab_bar| { - if let Some(open_aside_right) = open_aside_right - && render_aside_toggle_right - { - tab_bar.end_child(open_aside_right) - } else { - tab_bar - } - }) - } - fn render_single_row_tab_bar( &mut self, pinned_tabs: Vec, @@ -3547,10 +3413,6 @@ impl Pane { tab_count: usize, navigate_backward: IconButton, navigate_forward: IconButton, - open_aside_left: Option, - open_aside_right: Option, - render_aside_toggle_left: bool, - render_aside_toggle_right: bool, window: &mut Window, cx: &mut Context, ) -> AnyElement { @@ -3559,8 +3421,6 @@ impl Pane { TabBar::new("tab_bar"), navigate_backward, navigate_forward, - open_aside_left, - render_aside_toggle_left, window, cx, ) @@ -3581,8 +3441,7 @@ impl Pane { }) })) .child(self.render_unpinned_tabs_container(unpinned_tabs, tab_count, cx)); - Self::configure_tab_bar_end(tab_bar, open_aside_right, render_aside_toggle_right) - .into_any_element() + tab_bar.into_any_element() } fn render_two_row_tab_bar( @@ -3592,10 +3451,6 @@ impl Pane { tab_count: usize, navigate_backward: IconButton, navigate_forward: IconButton, - open_aside_left: Option, - open_aside_right: Option, - render_aside_toggle_left: bool, - render_aside_toggle_right: bool, window: &mut Window, cx: &mut Context, ) -> AnyElement { @@ -3604,8 +3459,6 @@ impl Pane { TabBar::new("pinned_tab_bar"), navigate_backward, navigate_forward, - open_aside_left, - render_aside_toggle_left, window, cx, ) @@ -3617,12 +3470,6 @@ impl Pane { .w_full() .children(pinned_tabs), ); - let pinned_tab_bar = Self::configure_tab_bar_end( - pinned_tab_bar, - open_aside_right, - render_aside_toggle_right, - ); - v_flex() .w_full() .flex_none() @@ -7561,8 +7408,8 @@ mod tests { let scroll_bounds = tab_bar_scroll_handle.bounds(); let scroll_offset = tab_bar_scroll_handle.offset(); assert!(tab_bounds.right() <= scroll_bounds.right()); - // -43.0 is the magic number for this setup - assert_eq!(scroll_offset.x, px(-43.0)); + // -38.5 is the magic number for this setup + assert_eq!(scroll_offset.x, px(-38.5)); assert!( !tab_bounds.intersects(&new_tab_button_bounds), "Tab should not overlap with the new tab button, if this is failing check if there's been a redesign!" diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 393ed74e30c9c34bf7cdb22aabf2de2d05aa84f8..0f8cef616f5ed03c31eaf3511c58922ae230e385 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -206,7 +206,7 @@ impl PaneGroup { } pub fn mark_positions(&mut self, cx: &mut App) { - self.root.mark_positions(self.is_center, true, true, cx); + self.root.mark_positions(self.is_center, cx); } pub fn render( @@ -278,37 +278,15 @@ pub enum Member { } impl Member { - pub fn mark_positions( - &mut self, - in_center_group: bool, - is_upper_left: bool, - is_upper_right: bool, - cx: &mut App, - ) { + pub fn mark_positions(&mut self, in_center_group: bool, cx: &mut App) { match self { Member::Axis(pane_axis) => { - let len = pane_axis.members.len(); - for (idx, member) in pane_axis.members.iter_mut().enumerate() { - let member_upper_left = match pane_axis.axis { - Axis::Vertical => is_upper_left && idx == 0, - Axis::Horizontal => is_upper_left && idx == 0, - }; - let member_upper_right = match pane_axis.axis { - Axis::Vertical => is_upper_right && idx == 0, - Axis::Horizontal => is_upper_right && idx == len - 1, - }; - member.mark_positions( - in_center_group, - member_upper_left, - member_upper_right, - cx, - ); + for member in pane_axis.members.iter_mut() { + member.mark_positions(in_center_group, cx); } } Member::Pane(entity) => entity.update(cx, |pane, _| { pane.in_center_group = in_center_group; - pane.is_upper_left = is_upper_left; - pane.is_upper_right = is_upper_right; }), } } diff --git a/crates/workspace/src/utility_pane.rs b/crates/workspace/src/utility_pane.rs deleted file mode 100644 index 2760000216d9164367c58d41d4f1b1893dc8cd75..0000000000000000000000000000000000000000 --- a/crates/workspace/src/utility_pane.rs +++ /dev/null @@ -1,282 +0,0 @@ -use gpui::{ - AppContext as _, EntityId, MouseButton, Pixels, Render, StatefulInteractiveElement, - Subscription, WeakEntity, deferred, px, -}; -use ui::{ - ActiveTheme as _, Context, FluentBuilder as _, InteractiveElement as _, IntoElement, - ParentElement as _, RenderOnce, Styled as _, Window, div, -}; - -use crate::{ - DockPosition, Workspace, - dock::{ClosePane, MinimizePane, UtilityPane, UtilityPaneHandle}, -}; - -pub(crate) const UTILITY_PANE_RESIZE_HANDLE_SIZE: Pixels = px(6.0); -pub(crate) const UTILITY_PANE_MIN_WIDTH: Pixels = px(20.0); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum UtilityPaneSlot { - Left, - Right, -} - -struct UtilityPaneSlotState { - panel_id: EntityId, - utility_pane: Box, - _subscriptions: Vec, -} - -#[derive(Default)] -pub struct UtilityPaneState { - left_slot: Option, - right_slot: Option, -} - -#[derive(Clone)] -pub struct DraggedUtilityPane(pub UtilityPaneSlot); - -impl Render for DraggedUtilityPane { - fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { - gpui::Empty - } -} - -pub fn utility_slot_for_dock_position(position: DockPosition) -> UtilityPaneSlot { - match position { - DockPosition::Left => UtilityPaneSlot::Left, - DockPosition::Right => UtilityPaneSlot::Right, - DockPosition::Bottom => UtilityPaneSlot::Left, - } -} - -impl Workspace { - pub fn utility_pane(&self, slot: UtilityPaneSlot) -> Option<&dyn UtilityPaneHandle> { - match slot { - UtilityPaneSlot::Left => self - .utility_panes - .left_slot - .as_ref() - .map(|s| s.utility_pane.as_ref()), - UtilityPaneSlot::Right => self - .utility_panes - .right_slot - .as_ref() - .map(|s| s.utility_pane.as_ref()), - } - } - - pub fn toggle_utility_pane( - &mut self, - slot: UtilityPaneSlot, - window: &mut Window, - cx: &mut Context, - ) { - if let Some(handle) = self.utility_pane(slot) { - let current = handle.expanded(cx); - handle.set_expanded(!current, cx); - } - cx.notify(); - self.serialize_workspace(window, cx); - } - - pub fn register_utility_pane( - &mut self, - slot: UtilityPaneSlot, - panel_id: EntityId, - handle: gpui::Entity, - cx: &mut Context, - ) { - let minimize_subscription = - cx.subscribe(&handle, move |this, _, _event: &MinimizePane, cx| { - if let Some(handle) = this.utility_pane(slot) { - handle.set_expanded(false, cx); - } - cx.notify(); - }); - - let close_subscription = cx.subscribe(&handle, move |this, _, _event: &ClosePane, cx| { - this.clear_utility_pane(slot, cx); - }); - - let subscriptions = vec![minimize_subscription, close_subscription]; - let boxed_handle: Box = Box::new(handle); - - match slot { - UtilityPaneSlot::Left => { - self.utility_panes.left_slot = Some(UtilityPaneSlotState { - panel_id, - utility_pane: boxed_handle, - _subscriptions: subscriptions, - }); - } - UtilityPaneSlot::Right => { - self.utility_panes.right_slot = Some(UtilityPaneSlotState { - panel_id, - utility_pane: boxed_handle, - _subscriptions: subscriptions, - }); - } - } - cx.notify(); - } - - pub fn clear_utility_pane(&mut self, slot: UtilityPaneSlot, cx: &mut Context) { - match slot { - UtilityPaneSlot::Left => { - self.utility_panes.left_slot = None; - } - UtilityPaneSlot::Right => { - self.utility_panes.right_slot = None; - } - } - cx.notify(); - } - - pub fn clear_utility_pane_if_provider( - &mut self, - slot: UtilityPaneSlot, - provider_panel_id: EntityId, - cx: &mut Context, - ) { - let should_clear = match slot { - UtilityPaneSlot::Left => self - .utility_panes - .left_slot - .as_ref() - .is_some_and(|slot| slot.panel_id == provider_panel_id), - UtilityPaneSlot::Right => self - .utility_panes - .right_slot - .as_ref() - .is_some_and(|slot| slot.panel_id == provider_panel_id), - }; - - if should_clear { - self.clear_utility_pane(slot, cx); - } - } - - pub fn resize_utility_pane( - &mut self, - slot: UtilityPaneSlot, - new_width: Pixels, - window: &mut Window, - cx: &mut Context, - ) { - if let Some(handle) = self.utility_pane(slot) { - let max_width = self.max_utility_pane_width(window, cx); - let width = new_width.max(UTILITY_PANE_MIN_WIDTH).min(max_width); - handle.set_width(Some(width), cx); - cx.notify(); - self.serialize_workspace(window, cx); - } - } - - pub fn reset_utility_pane_width( - &mut self, - slot: UtilityPaneSlot, - window: &mut Window, - cx: &mut Context, - ) { - if let Some(handle) = self.utility_pane(slot) { - handle.set_width(None, cx); - cx.notify(); - self.serialize_workspace(window, cx); - } - } -} - -#[derive(IntoElement)] -pub struct UtilityPaneFrame { - workspace: WeakEntity, - slot: UtilityPaneSlot, - handle: Box, -} - -impl UtilityPaneFrame { - pub fn new( - slot: UtilityPaneSlot, - handle: Box, - cx: &mut Context, - ) -> Self { - let workspace = cx.weak_entity(); - Self { - workspace, - slot, - handle, - } - } -} - -impl RenderOnce for UtilityPaneFrame { - fn render(self, _window: &mut Window, cx: &mut ui::App) -> impl IntoElement { - let workspace = self.workspace.clone(); - let slot = self.slot; - let width = self.handle.width(cx); - - let create_resize_handle = || { - let workspace_handle = workspace.clone(); - let handle = div() - .id(match slot { - UtilityPaneSlot::Left => "utility-pane-resize-handle-left", - UtilityPaneSlot::Right => "utility-pane-resize-handle-right", - }) - .on_drag(DraggedUtilityPane(slot), move |pane, _, _, cx| { - cx.stop_propagation(); - cx.new(|_| pane.clone()) - }) - .on_mouse_down(MouseButton::Left, move |_, _, cx| { - cx.stop_propagation(); - }) - .on_mouse_up( - MouseButton::Left, - move |e: &gpui::MouseUpEvent, window, cx| { - if e.click_count == 2 { - workspace_handle - .update(cx, |workspace, cx| { - workspace.reset_utility_pane_width(slot, window, cx); - }) - .ok(); - cx.stop_propagation(); - } - }, - ) - .occlude(); - - match slot { - UtilityPaneSlot::Left => deferred( - handle - .absolute() - .right(-UTILITY_PANE_RESIZE_HANDLE_SIZE / 2.) - .top(px(0.)) - .h_full() - .w(UTILITY_PANE_RESIZE_HANDLE_SIZE) - .cursor_col_resize(), - ), - UtilityPaneSlot::Right => deferred( - handle - .absolute() - .left(-UTILITY_PANE_RESIZE_HANDLE_SIZE / 2.) - .top(px(0.)) - .h_full() - .w(UTILITY_PANE_RESIZE_HANDLE_SIZE) - .cursor_col_resize(), - ), - } - }; - - div() - .h_full() - .bg(cx.theme().colors().tab_bar_background) - .w(width) - .border_color(cx.theme().colors().border) - .when(self.slot == UtilityPaneSlot::Left, |this| this.border_r_1()) - .when(self.slot == UtilityPaneSlot::Right, |this| { - this.border_l_1() - }) - .child(create_resize_handle()) - .child(self.handle.to_any()) - .into_any_element() - } -} diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index ca79f6364a1f36475af115e5beefb18df7c394f0..85f4a9d8e0eed422c13715f05be72a05b841f0e9 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -17,7 +17,6 @@ pub mod tasks; mod theme_preview; mod toast_layer; mod toolbar; -pub mod utility_pane; pub mod welcome; mod workspace_settings; @@ -39,7 +38,6 @@ use client::{ }; use collections::{HashMap, HashSet, hash_map}; use dock::{Dock, DockPosition, PanelButtons, PanelHandle, RESIZE_HANDLE_SIZE}; -use feature_flags::{AgentV2FeatureFlag, FeatureFlagAppExt}; use futures::{ Future, FutureExt, StreamExt, channel::{ @@ -143,18 +141,13 @@ pub use workspace_settings::{ }; use zed_actions::{Spawn, feedback::FileBugReport}; -use crate::{ - item::ItemBufferKind, - notifications::NotificationId, - utility_pane::{UTILITY_PANE_MIN_WIDTH, utility_slot_for_dock_position}, -}; +use crate::{item::ItemBufferKind, notifications::NotificationId}; use crate::{ persistence::{ SerializedAxis, model::{DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup}, }, security_modal::SecurityModal, - utility_pane::{DraggedUtilityPane, UtilityPaneFrame, UtilityPaneSlot, UtilityPaneState}, }; pub const SERIALIZATION_THROTTLE_TIME: Duration = Duration::from_millis(200); @@ -1266,7 +1259,6 @@ pub struct Workspace { scheduled_tasks: Vec>, last_open_dock_positions: Vec, removing: bool, - utility_panes: UtilityPaneState, } impl EventEmitter for Workspace {} @@ -1695,7 +1687,6 @@ impl Workspace { scheduled_tasks: Vec::new(), last_open_dock_positions: Vec::new(), removing: false, - utility_panes: UtilityPaneState::default(), } } @@ -2022,18 +2013,8 @@ impl Workspace { window: &mut Window, cx: &mut Context, ) { - let mut found_in_dock = None; for dock in [&self.left_dock, &self.bottom_dock, &self.right_dock] { - let found = dock.update(cx, |dock, cx| dock.remove_panel(panel, window, cx)); - - if found { - found_in_dock = Some(dock.clone()); - } - } - if let Some(found_in_dock) = found_in_dock { - let position = found_in_dock.read(cx).position(); - let slot = utility_slot_for_dock_position(position); - self.clear_utility_pane_if_provider(slot, Entity::entity_id(panel), cx); + dock.update(cx, |dock, cx| dock.remove_panel(panel, window, cx)); } } @@ -6903,7 +6884,6 @@ impl Workspace { left_dock.resize_active_panel(Some(size), window, cx); } }); - self.clamp_utility_pane_widths(window, cx); } fn resize_right_dock(&mut self, new_size: Pixels, window: &mut Window, cx: &mut App) { @@ -6926,7 +6906,6 @@ impl Workspace { right_dock.resize_active_panel(Some(size), window, cx); } }); - self.clamp_utility_pane_widths(window, cx); } fn resize_bottom_dock(&mut self, new_size: Pixels, window: &mut Window, cx: &mut App) { @@ -6941,42 +6920,6 @@ impl Workspace { bottom_dock.resize_active_panel(Some(size), window, cx); } }); - self.clamp_utility_pane_widths(window, cx); - } - - fn max_utility_pane_width(&self, window: &Window, cx: &App) -> Pixels { - let left_dock_width = self - .left_dock - .read(cx) - .active_panel_size(window, cx) - .unwrap_or(px(0.0)); - let right_dock_width = self - .right_dock - .read(cx) - .active_panel_size(window, cx) - .unwrap_or(px(0.0)); - let center_pane_width = self.bounds.size.width - left_dock_width - right_dock_width; - center_pane_width - px(10.0) - } - - fn clamp_utility_pane_widths(&mut self, window: &mut Window, cx: &mut App) { - let max_width = self.max_utility_pane_width(window, cx); - - // Clamp left slot utility pane if it exists - if let Some(handle) = self.utility_pane(UtilityPaneSlot::Left) { - let current_width = handle.width(cx); - if current_width > max_width { - handle.set_width(Some(max_width.max(UTILITY_PANE_MIN_WIDTH)), cx); - } - } - - // Clamp right slot utility pane if it exists - if let Some(handle) = self.utility_pane(UtilityPaneSlot::Right) { - let current_width = handle.width(cx); - if current_width > max_width { - handle.set_width(Some(max_width.max(UTILITY_PANE_MIN_WIDTH)), cx); - } - } } fn toggle_edit_predictions_all_files( @@ -7483,34 +7426,7 @@ impl Render for Workspace { } }, )) - .on_drag_move(cx.listener( - move |workspace, - e: &DragMoveEvent, - window, - cx| { - let slot = e.drag(cx).0; - match slot { - UtilityPaneSlot::Left => { - let left_dock_width = workspace.left_dock.read(cx) - .active_panel_size(window, cx) - .unwrap_or(gpui::px(0.0)); - let new_width = e.event.position.x - - workspace.bounds.left() - - left_dock_width; - workspace.resize_utility_pane(slot, new_width, window, cx); - } - UtilityPaneSlot::Right => { - let right_dock_width = workspace.right_dock.read(cx) - .active_panel_size(window, cx) - .unwrap_or(gpui::px(0.0)); - let new_width = workspace.bounds.right() - - e.event.position.x - - right_dock_width; - workspace.resize_utility_pane(slot, new_width, window, cx); - } - } - }, - )) + }) .child({ match bottom_dock_layout { @@ -7530,15 +7446,7 @@ impl Render for Workspace { window, cx, )) - .when(cx.has_flag::(), |this| { - this.when_some(self.utility_pane(UtilityPaneSlot::Left), |this, pane| { - this.when(pane.expanded(cx), |this| { - this.child( - UtilityPaneFrame::new(UtilityPaneSlot::Left, pane.box_clone(), cx) - ) - }) - }) - }) + .child( div() .flex() @@ -7580,15 +7488,7 @@ impl Render for Workspace { ), ), ) - .when(cx.has_flag::(), |this| { - this.when_some(self.utility_pane(UtilityPaneSlot::Right), |this, pane| { - this.when(pane.expanded(cx), |this| { - this.child( - UtilityPaneFrame::new(UtilityPaneSlot::Right, pane.box_clone(), cx) - ) - }) - }) - }) + .children(self.render_dock( DockPosition::Right, &self.right_dock, @@ -7619,15 +7519,7 @@ impl Render for Workspace { .flex_row() .flex_1() .children(self.render_dock(DockPosition::Left, &self.left_dock, window, cx)) - .when(cx.has_flag::(), |this| { - this.when_some(self.utility_pane(UtilityPaneSlot::Left), |this, pane| { - this.when(pane.expanded(cx), |this| { - this.child( - UtilityPaneFrame::new(UtilityPaneSlot::Left, pane.box_clone(), cx) - ) - }) - }) - }) + .child( div() .flex() @@ -7655,13 +7547,7 @@ impl Render for Workspace { .when_some(paddings.1, |this, p| this.child(p.border_l_1())), ) ) - .when_some(self.utility_pane(UtilityPaneSlot::Right), |this, pane| { - this.when(pane.expanded(cx), |this| { - this.child( - UtilityPaneFrame::new(UtilityPaneSlot::Right, pane.box_clone(), cx) - ) - }) - }) + ) .child( div() @@ -7686,15 +7572,7 @@ impl Render for Workspace { window, cx, )) - .when(cx.has_flag::(), |this| { - this.when_some(self.utility_pane(UtilityPaneSlot::Left), |this, pane| { - this.when(pane.expanded(cx), |this| { - this.child( - UtilityPaneFrame::new(UtilityPaneSlot::Left, pane.box_clone(), cx) - ) - }) - }) - }) + .child( div() .flex() @@ -7733,15 +7611,7 @@ impl Render for Workspace { .when_some(paddings.1, |this, p| this.child(p.border_l_1())), ) ) - .when(cx.has_flag::(), |this| { - this.when_some(self.utility_pane(UtilityPaneSlot::Right), |this, pane| { - this.when(pane.expanded(cx), |this| { - this.child( - UtilityPaneFrame::new(UtilityPaneSlot::Right, pane.box_clone(), cx) - ) - }) - }) - }) + .children(self.render_dock(DockPosition::Right, &self.right_dock, window, cx)) ) .child( @@ -7761,13 +7631,7 @@ impl Render for Workspace { window, cx, )) - .when_some(self.utility_pane(UtilityPaneSlot::Left), |this, pane| { - this.when(pane.expanded(cx), |this| { - this.child( - UtilityPaneFrame::new(UtilityPaneSlot::Left, pane.box_clone(), cx) - ) - }) - }) + .child( div() .flex() @@ -7805,15 +7669,7 @@ impl Render for Workspace { cx, )), ) - .when(cx.has_flag::(), |this| { - this.when_some(self.utility_pane(UtilityPaneSlot::Right), |this, pane| { - this.when(pane.expanded(cx), |this| { - this.child( - UtilityPaneFrame::new(UtilityPaneSlot::Right, pane.box_clone(), cx) - ) - }) - }) - }) + .children(self.render_dock( DockPosition::Right, &self.right_dock, diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 924352c46a5655813a11f7bff160f093fc94a540..8315bf76cafd30fa275c263ca73072278cce918e 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -69,7 +69,6 @@ agent.workspace = true agent-client-protocol.workspace = true agent_settings.workspace = true agent_ui.workspace = true -agent_ui_v2.workspace = true anyhow.workspace = true askpass.workspace = true assets.workspace = true @@ -257,7 +256,6 @@ title_bar = { workspace = true, features = ["test-support"] } workspace = { workspace = true, features = ["test-support"] } image.workspace = true agent_ui = { workspace = true, features = ["test-support"] } -agent_ui_v2 = { workspace = true, features = ["test-support"] } search = { workspace = true, features = ["test-support"] } repl = { workspace = true, features = ["test-support"] } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index c88a83b180d4107abf4573ab46619f4687937418..09264e7799d25f23a91bb014ea4dff0a3283ab74 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -634,7 +634,7 @@ fn main() { false, cx, ); - agent_ui_v2::agents_panel::init(cx); + repl::init(app_state.fs.clone(), cx); recent_projects::init(cx); dev_container::init(cx); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 6632959b9b84ab561e23aa5248776b0ca1521618..c790a410585a6d439ab5e33c28a69cecd926ac44 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -14,7 +14,6 @@ pub mod visual_tests; pub(crate) mod windows_only_instance; use agent_ui::{AgentDiffToolbar, AgentPanelDelegate}; -use agent_ui_v2::agents_panel::AgentsPanel; use anyhow::Context as _; pub use app_menus::*; use assets::Assets; @@ -87,7 +86,7 @@ use vim_mode_setting::VimModeSetting; use workspace::notifications::{ NotificationId, SuppressEvent, dismiss_app_notification, show_app_notification, }; -use workspace::utility_pane::utility_slot_for_dock_position; + use workspace::{ AppState, MultiWorkspace, NewFile, NewWindow, OpenLog, Panel, Toast, Workspace, WorkspaceSettings, create_and_open_local_file, @@ -657,8 +656,7 @@ fn initialize_panels( add_panel_when_ready(channels_panel, workspace_handle.clone(), cx.clone()), add_panel_when_ready(notification_panel, workspace_handle.clone(), cx.clone()), add_panel_when_ready(debug_panel, workspace_handle.clone(), cx.clone()), - initialize_agent_panel(workspace_handle.clone(), prompt_builder, cx.clone()).map(|r| r.log_err()), - initialize_agents_panel(workspace_handle, cx.clone()).map(|r| r.log_err()) + initialize_agent_panel(workspace_handle, prompt_builder, cx.clone()).map(|r| r.log_err()), ); anyhow::Ok(()) @@ -748,31 +746,6 @@ async fn initialize_agent_panel( anyhow::Ok(()) } -async fn initialize_agents_panel( - workspace_handle: WeakEntity, - mut cx: AsyncWindowContext, -) -> anyhow::Result<()> { - workspace_handle - .update_in(&mut cx, |workspace, window, cx| { - setup_or_teardown_ai_panel(workspace, window, cx, |workspace, cx| { - AgentsPanel::load(workspace, cx) - }) - })? - .await?; - - workspace_handle.update_in(&mut cx, |_workspace, window, cx| { - cx.observe_global_in::(window, move |workspace, window, cx| { - setup_or_teardown_ai_panel(workspace, window, cx, |workspace, cx| { - AgentsPanel::load(workspace, cx) - }) - .detach_and_log_err(cx); - }) - .detach(); - })?; - - anyhow::Ok(()) -} - fn register_actions( app_state: Arc, workspace: &mut Workspace, @@ -1067,18 +1040,6 @@ fn register_actions( workspace.toggle_panel_focus::(window, cx); }, ) - .register_action( - |workspace: &mut Workspace, - _: &zed_actions::agent::ToggleAgentPane, - window: &mut Window, - cx: &mut Context| { - if let Some(panel) = workspace.panel::(cx) { - let position = panel.read(cx).position(window, cx); - let slot = utility_slot_for_dock_position(position); - workspace.toggle_utility_pane(slot, window, cx); - } - }, - ) .register_action({ let app_state = Arc::downgrade(&app_state); move |_, _: &NewWindow, _, cx| { @@ -4826,7 +4787,6 @@ mod tests { "action", "activity_indicator", "agent", - "agents", "app_menu", "assistant", "assistant2", @@ -5071,7 +5031,7 @@ mod tests { false, cx, ); - agent_ui_v2::agents_panel::init(cx); + repl::init(app_state.fs.clone(), cx); repl::notebook::init(cx); tasks_ui::init(cx); diff --git a/crates/zed_actions/src/lib.rs b/crates/zed_actions/src/lib.rs index 874cb569a2d43065e091fe94cbe9575d0e24d8ba..136977f95f60a903990fceffec5d595b7221d253 100644 --- a/crates/zed_actions/src/lib.rs +++ b/crates/zed_actions/src/lib.rs @@ -450,8 +450,6 @@ pub mod agent { AddSelectionToThread, /// Resets the agent panel zoom levels (agent UI and buffer font sizes). ResetAgentZoom, - /// Toggles the utility/agent pane open/closed state. - ToggleAgentPane, /// Pastes clipboard content without any formatting. PasteRaw, ]