Detailed changes
@@ -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",
@@ -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" }
@@ -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.
@@ -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,
@@ -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<LanguageModelSelection>,
@@ -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()),
@@ -431,9 +431,6 @@ fn update_command_palette_filter(cx: &mut App) {
filter.show_namespace("zed_predict_onboarding");
filter.show_action_types(&[TypeId::of::<zed_actions::OpenZedPredictOnboarding>()]);
- if !agent_v2_enabled {
- filter.hide_action_types(&[TypeId::of::<zed_actions::agent::ToggleAgentPane>()]);
- }
}
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,
@@ -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"] }
@@ -1 +0,0 @@
-../../LICENSE-GPL
@@ -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<acp::SessionId> 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<Pixels>,
- pub thread_id: Option<SerializedHistoryEntryId>,
-}
-
-pub enum AgentsUtilityPaneEvent {
- StateChanged,
-}
-
-impl EventEmitter<AgentsUtilityPaneEvent> for AgentThreadPane {}
-impl EventEmitter<MinimizePane> for AgentThreadPane {}
-impl EventEmitter<ClosePane> for AgentThreadPane {}
-
-struct ActiveThreadView {
- view: Entity<AcpServerView>,
- thread_id: acp::SessionId,
- _notify: Subscription,
-}
-
-pub struct AgentThreadPane {
- focus_handle: gpui::FocusHandle,
- expanded: bool,
- width: Option<Pixels>,
- thread_view: Option<ActiveThreadView>,
- workspace: WeakEntity<Workspace>,
- history: Entity<AcpThreadHistory>,
-}
-
-impl AgentThreadPane {
- pub fn new(
- workspace: WeakEntity<Workspace>,
- history: Entity<AcpThreadHistory>,
- cx: &mut ui::Context<Self>,
- ) -> 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<acp::SessionId> {
- 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<dyn Fs>,
- workspace: WeakEntity<Workspace>,
- project: Entity<Project>,
- thread_store: Entity<ThreadStore>,
- prompt_store: Option<Entity<PromptStore>>,
- window: &mut Window,
- cx: &mut Context<Self>,
- ) {
- let thread_id = entry.session_id.clone();
- let resume_thread = Some(entry);
-
- let agent: Rc<dyn AgentServer> = 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<Self>) -> 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<Workspace>| {
- 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>) {
- 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<Pixels>, cx: &mut Context<Self>) {
- self.width = width;
- cx.emit(AgentsUtilityPaneEvent::StateChanged);
- cx.notify();
- }
-}
-
-impl Render for AgentThreadPane {
- fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> 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)
- }
-}
@@ -1,3 +0,0 @@
-mod agent_thread_pane;
-
-pub mod agents_panel;
@@ -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<Pixels>,
- pane: Option<SerializedAgentThreadPane>,
-}
-
-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::<AgentsPanel>(window, cx);
- });
- })
- .detach();
-}
-
-pub struct AgentsPanel {
- focus_handle: gpui::FocusHandle,
- workspace: WeakEntity<Workspace>,
- project: Entity<Project>,
- agent_thread_pane: Option<Entity<AgentThreadPane>>,
- history: Entity<AcpThreadHistory>,
- thread_store: Entity<ThreadStore>,
- prompt_store: Option<Entity<PromptStore>>,
- fs: Arc<dyn Fs>,
- width: Option<Pixels>,
- pending_restore: Option<SerializedAgentThreadPane>,
- pending_serialization: Task<Option<()>>,
- _subscriptions: Vec<Subscription>,
-}
-
-impl AgentsPanel {
- pub fn load(
- workspace: WeakEntity<Workspace>,
- cx: AsyncWindowContext,
- ) -> Task<Result<Entity<Self>, 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::<SerializedAgentsPanel>(&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<Workspace>,
- fs: Arc<dyn Fs>,
- project: Entity<Project>,
- prompt_store: Option<Entity<PromptStore>>,
- window: &mut Window,
- cx: &mut ui::Context<Self>,
- ) -> 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<Self>,
- ) {
- 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<AgentThreadPane>,
- event: &AgentsUtilityPaneEvent,
- cx: &mut Context<Self>,
- ) {
- match event {
- AgentsUtilityPaneEvent::StateChanged => {
- self.serialize(cx);
- cx.notify();
- }
- }
- }
-
- fn handle_close_pane_event(
- &mut self,
- _utility_pane: Entity<AgentThreadPane>,
- _event: &ClosePane,
- cx: &mut Context<Self>,
- ) {
- self.agent_thread_pane = None;
- self.serialize(cx);
- cx.notify();
- }
-
- fn handle_history_updated(
- &mut self,
- _history: Entity<AcpThreadHistory>,
- window: &mut Window,
- cx: &mut Context<Self>,
- ) {
- self.maybe_restore_pending(window, cx);
- }
-
- fn handle_history_event(
- &mut self,
- _history: &Entity<AcpThreadHistory>,
- event: &ThreadHistoryEvent,
- window: &mut Window,
- cx: &mut Context<Self>,
- ) {
- 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<Self>) {
- 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<Pixels>,
- window: &mut Window,
- cx: &mut Context<Self>,
- ) {
- 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<Self>) {
- 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<Self>) {
- 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<PanelEvent> 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<Self>,
- ) {
- 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<Pixels>, window: &mut Window, cx: &mut Context<Self>) {
- 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<IconName> {
- (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<dyn Action> {
- Box::new(ToggleAgentsPanel)
- }
-
- fn activation_priority(&self) -> u32 {
- 4
- }
-
- fn enabled(&self, cx: &App) -> bool {
- AgentSettings::get_global(cx).enabled(cx) && cx.has_flag::<AgentV2FeatureFlag>()
- }
-}
-
-impl Render for AgentsPanel {
- fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
- gpui::div().size_full().child(self.history.clone())
- }
-}
@@ -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<DockPosition>,
- /// Where to dock the utility pane (the thread view pane).
- ///
- /// Default: left
- pub agents_panel_dock: Option<DockSide>,
/// Default width in pixels when the agent panel is docked to the left or right.
///
/// Default: 640
@@ -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<ScrollHandle>,
}
@@ -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<Item = impl IntoElement>) -> 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),
+ )
+ })
}
}
@@ -27,72 +27,6 @@ pub enum PanelEvent {
pub use proto::PanelId;
-pub struct MinimizePane;
-pub struct ClosePane;
-
-pub trait UtilityPane: EventEmitter<MinimizePane> + EventEmitter<ClosePane> + 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<Self>);
- fn width(&self, cx: &App) -> Pixels;
- fn set_width(&mut self, width: Option<Pixels>, cx: &mut Context<Self>);
-}
-
-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<Pixels>, cx: &mut App);
- fn to_any(&self) -> AnyView;
- fn box_clone(&self) -> Box<dyn UtilityPaneHandle>;
-}
-
-impl<T> UtilityPaneHandle for Entity<T>
-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<Pixels>, 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<dyn UtilityPaneHandle> {
- Box::new(self.clone())
- }
-}
-
-pub enum UtilityPanePosition {
- Left,
- Right,
-}
-
pub trait Panel: Focusable + EventEmitter<PanelEvent> + Render + Sized {
fn persistent_name() -> &'static str;
fn panel_key() -> &'static str;
@@ -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<Entity<crate::welcome::WelcomePage>>,
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<Pane>) -> 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::<AgentV2FeatureFlag>()
- && 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::<AgentV2FeatureFlag>()
- && 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<AnyElement>,
- render_aside_toggle_left: bool,
window: &mut Window,
cx: &mut Context<Pane>,
) -> 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<AnyElement>,
- 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<AnyElement>,
@@ -3547,10 +3413,6 @@ impl Pane {
tab_count: usize,
navigate_backward: IconButton,
navigate_forward: IconButton,
- open_aside_left: Option<AnyElement>,
- open_aside_right: Option<AnyElement>,
- render_aside_toggle_left: bool,
- render_aside_toggle_right: bool,
window: &mut Window,
cx: &mut Context<Pane>,
) -> 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<AnyElement>,
- open_aside_right: Option<AnyElement>,
- render_aside_toggle_left: bool,
- render_aside_toggle_right: bool,
window: &mut Window,
cx: &mut Context<Pane>,
) -> 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!"
@@ -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;
}),
}
}
@@ -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<dyn UtilityPaneHandle>,
- _subscriptions: Vec<Subscription>,
-}
-
-#[derive(Default)]
-pub struct UtilityPaneState {
- left_slot: Option<UtilityPaneSlotState>,
- right_slot: Option<UtilityPaneSlotState>,
-}
-
-#[derive(Clone)]
-pub struct DraggedUtilityPane(pub UtilityPaneSlot);
-
-impl Render for DraggedUtilityPane {
- fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> 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<Self>,
- ) {
- 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<T: UtilityPane>(
- &mut self,
- slot: UtilityPaneSlot,
- panel_id: EntityId,
- handle: gpui::Entity<T>,
- cx: &mut Context<Self>,
- ) {
- 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<dyn UtilityPaneHandle> = 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<Self>) {
- 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<Self>,
- ) {
- 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<Self>,
- ) {
- 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<Self>,
- ) {
- 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<Workspace>,
- slot: UtilityPaneSlot,
- handle: Box<dyn UtilityPaneHandle>,
-}
-
-impl UtilityPaneFrame {
- pub fn new(
- slot: UtilityPaneSlot,
- handle: Box<dyn UtilityPaneHandle>,
- cx: &mut Context<Workspace>,
- ) -> 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()
- }
-}
@@ -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<Task<()>>,
last_open_dock_positions: Vec<DockPosition>,
removing: bool,
- utility_panes: UtilityPaneState,
}
impl EventEmitter<Event> 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<Self>,
) {
- 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<DraggedUtilityPane>,
- 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::<AgentV2FeatureFlag>(), |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::<AgentV2FeatureFlag>(), |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::<AgentV2FeatureFlag>(), |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::<AgentV2FeatureFlag>(), |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::<AgentV2FeatureFlag>(), |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::<AgentV2FeatureFlag>(), |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,
@@ -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"] }
@@ -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);
@@ -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<Workspace>,
- 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::<SettingsStore>(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<AppState>,
workspace: &mut Workspace,
@@ -1067,18 +1040,6 @@ fn register_actions(
workspace.toggle_panel_focus::<TerminalPanel>(window, cx);
},
)
- .register_action(
- |workspace: &mut Workspace,
- _: &zed_actions::agent::ToggleAgentPane,
- window: &mut Window,
- cx: &mut Context<Workspace>| {
- if let Some(panel) = workspace.panel::<AgentsPanel>(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);
@@ -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,
]