@@ -7,7 +7,7 @@ use crate::{
ViewId, Workspace, WorkspaceId,
};
use anyhow::Result;
-use client2::{
+use client::{
proto::{self, PeerId},
Client,
};
@@ -16,10 +16,10 @@ use gpui::{
HighlightStyle, Model, Pixels, Point, SharedString, Task, View, ViewContext, WeakView,
WindowContext,
};
-use project2::{Project, ProjectEntryId, ProjectPath};
+use project::{Project, ProjectEntryId, ProjectPath};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings2::Settings;
+use settings::Settings;
use smallvec::SmallVec;
use std::{
any::{Any, TypeId},
@@ -33,7 +33,7 @@ use std::{
},
time::Duration,
};
-use theme2::Theme;
+use theme::Theme;
#[derive(Deserialize)]
pub struct ItemSettings {
@@ -110,7 +110,7 @@ pub trait Item: FocusableView + EventEmitter<ItemEvent> {
fn for_each_project_item(
&self,
_: &AppContext,
- _: &mut dyn FnMut(EntityId, &dyn project2::Item),
+ _: &mut dyn FnMut(EntityId, &dyn project::Item),
) {
}
fn is_singleton(&self, _cx: &AppContext) -> bool {
@@ -222,7 +222,7 @@ pub trait ItemHandle: 'static + Send {
fn for_each_project_item(
&self,
_: &AppContext,
- _: &mut dyn FnMut(EntityId, &dyn project2::Item),
+ _: &mut dyn FnMut(EntityId, &dyn project::Item),
);
fn is_singleton(&self, cx: &AppContext) -> bool;
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
@@ -347,7 +347,7 @@ impl<T: Item> ItemHandle for View<T> {
fn for_each_project_item(
&self,
cx: &AppContext,
- f: &mut dyn FnMut(EntityId, &dyn project2::Item),
+ f: &mut dyn FnMut(EntityId, &dyn project::Item),
) {
self.read(cx).for_each_project_item(cx, f)
}
@@ -375,6 +375,7 @@ impl<T: Item> ItemHandle for View<T> {
pane: View<Pane>,
cx: &mut ViewContext<Workspace>,
) {
+ let weak_item = self.downgrade();
let history = pane.read(cx).nav_history_for_item(self);
self.update(cx, |this, cx| {
this.set_nav_history(history, cx);
@@ -491,16 +492,15 @@ impl<T: Item> ItemHandle for View<T> {
}
}));
- // todo!()
- // cx.observe_focus(self, move |workspace, item, focused, cx| {
- // if !focused
- // && WorkspaceSettings::get_global(cx).autosave == AutosaveSetting::OnFocusChange
- // {
- // Pane::autosave_item(&item, workspace.project.clone(), cx)
- // .detach_and_log_err(cx);
- // }
- // })
- // .detach();
+ cx.on_blur(&self.focus_handle(cx), move |workspace, cx| {
+ if WorkspaceSettings::get_global(cx).autosave == AutosaveSetting::OnFocusChange {
+ if let Some(item) = weak_item.upgrade() {
+ Pane::autosave_item(&item, workspace.project.clone(), cx)
+ .detach_and_log_err(cx);
+ }
+ }
+ })
+ .detach();
let item_id = self.item_id();
cx.observe_release(self, move |workspace, _, _| {
@@ -640,7 +640,7 @@ impl<T: Item> WeakItemHandle for WeakView<T> {
}
pub trait ProjectItem: Item {
- type Item: project2::Item;
+ type Item: project::Item;
fn for_project_item(
project: Model<Project>,
@@ -759,300 +759,310 @@ impl<T: FollowableItem> FollowableItemHandle for View<T> {
}
}
-// #[cfg(any(test, feature = "test-support"))]
-// pub mod test {
-// use super::{Item, ItemEvent};
-// use crate::{ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId};
-// use gpui::{
-// elements::Empty, AnyElement, AppContext, Element, Entity, Model, Task, View,
-// ViewContext, View, WeakViewHandle,
-// };
-// use project2::{Project, ProjectEntryId, ProjectPath, WorktreeId};
-// use smallvec::SmallVec;
-// use std::{any::Any, borrow::Cow, cell::Cell, path::Path};
-
-// pub struct TestProjectItem {
-// pub entry_id: Option<ProjectEntryId>,
-// pub project_path: Option<ProjectPath>,
-// }
-
-// pub struct TestItem {
-// pub workspace_id: WorkspaceId,
-// pub state: String,
-// pub label: String,
-// pub save_count: usize,
-// pub save_as_count: usize,
-// pub reload_count: usize,
-// pub is_dirty: bool,
-// pub is_singleton: bool,
-// pub has_conflict: bool,
-// pub project_items: Vec<Model<TestProjectItem>>,
-// pub nav_history: Option<ItemNavHistory>,
-// pub tab_descriptions: Option<Vec<&'static str>>,
-// pub tab_detail: Cell<Option<usize>>,
-// }
-
-// impl Entity for TestProjectItem {
-// type Event = ();
-// }
-
-// impl project2::Item for TestProjectItem {
-// fn entry_id(&self, _: &AppContext) -> Option<ProjectEntryId> {
-// self.entry_id
-// }
-
-// fn project_path(&self, _: &AppContext) -> Option<ProjectPath> {
-// self.project_path.clone()
-// }
-// }
-
-// pub enum TestItemEvent {
-// Edit,
-// }
-
-// impl Clone for TestItem {
-// fn clone(&self) -> Self {
-// Self {
-// state: self.state.clone(),
-// label: self.label.clone(),
-// save_count: self.save_count,
-// save_as_count: self.save_as_count,
-// reload_count: self.reload_count,
-// is_dirty: self.is_dirty,
-// is_singleton: self.is_singleton,
-// has_conflict: self.has_conflict,
-// project_items: self.project_items.clone(),
-// nav_history: None,
-// tab_descriptions: None,
-// tab_detail: Default::default(),
-// workspace_id: self.workspace_id,
-// }
-// }
-// }
-
-// impl TestProjectItem {
-// pub fn new(id: u64, path: &str, cx: &mut AppContext) -> Model<Self> {
-// let entry_id = Some(ProjectEntryId::from_proto(id));
-// let project_path = Some(ProjectPath {
-// worktree_id: WorktreeId::from_usize(0),
-// path: Path::new(path).into(),
-// });
-// cx.add_model(|_| Self {
-// entry_id,
-// project_path,
-// })
-// }
-
-// pub fn new_untitled(cx: &mut AppContext) -> Model<Self> {
-// cx.add_model(|_| Self {
-// project_path: None,
-// entry_id: None,
-// })
-// }
-// }
-
-// impl TestItem {
-// pub fn new() -> Self {
-// Self {
-// state: String::new(),
-// label: String::new(),
-// save_count: 0,
-// save_as_count: 0,
-// reload_count: 0,
-// is_dirty: false,
-// has_conflict: false,
-// project_items: Vec::new(),
-// is_singleton: true,
-// nav_history: None,
-// tab_descriptions: None,
-// tab_detail: Default::default(),
-// workspace_id: 0,
-// }
-// }
-
-// pub fn new_deserialized(id: WorkspaceId) -> Self {
-// let mut this = Self::new();
-// this.workspace_id = id;
-// this
-// }
-
-// pub fn with_label(mut self, state: &str) -> Self {
-// self.label = state.to_string();
-// self
-// }
-
-// pub fn with_singleton(mut self, singleton: bool) -> Self {
-// self.is_singleton = singleton;
-// self
-// }
-
-// pub fn with_dirty(mut self, dirty: bool) -> Self {
-// self.is_dirty = dirty;
-// self
-// }
-
-// pub fn with_conflict(mut self, has_conflict: bool) -> Self {
-// self.has_conflict = has_conflict;
-// self
-// }
-
-// pub fn with_project_items(mut self, items: &[Model<TestProjectItem>]) -> Self {
-// self.project_items.clear();
-// self.project_items.extend(items.iter().cloned());
-// self
-// }
-
-// pub fn set_state(&mut self, state: String, cx: &mut ViewContext<Self>) {
-// self.push_to_nav_history(cx);
-// self.state = state;
-// }
-
-// fn push_to_nav_history(&mut self, cx: &mut ViewContext<Self>) {
-// if let Some(history) = &mut self.nav_history {
-// history.push(Some(Box::new(self.state.clone())), cx);
-// }
-// }
-// }
-
-// impl Entity for TestItem {
-// type Event = TestItemEvent;
-// }
-
-// impl View for TestItem {
-// fn ui_name() -> &'static str {
-// "TestItem"
-// }
-
-// fn render(&mut self, _: &mut ViewContext<Self>) -> AnyElement<Self> {
-// Empty::new().into_any()
-// }
-// }
-
-// impl Item for TestItem {
-// fn tab_description(&self, detail: usize, _: &AppContext) -> Option<Cow<str>> {
-// self.tab_descriptions.as_ref().and_then(|descriptions| {
-// let description = *descriptions.get(detail).or_else(|| descriptions.last())?;
-// Some(description.into())
-// })
-// }
-
-// fn tab_content<V: 'static>(
-// &self,
-// detail: Option<usize>,
-// _: &theme2::Tab,
-// _: &AppContext,
-// ) -> AnyElement<V> {
-// self.tab_detail.set(detail);
-// Empty::new().into_any()
-// }
-
-// fn for_each_project_item(
-// &self,
-// cx: &AppContext,
-// f: &mut dyn FnMut(usize, &dyn project2::Item),
-// ) {
-// self.project_items
-// .iter()
-// .for_each(|item| f(item.id(), item.read(cx)))
-// }
-
-// fn is_singleton(&self, _: &AppContext) -> bool {
-// self.is_singleton
-// }
-
-// fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
-// self.nav_history = Some(history);
-// }
-
-// fn navigate(&mut self, state: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {
-// let state = *state.downcast::<String>().unwrap_or_default();
-// if state != self.state {
-// self.state = state;
-// true
-// } else {
-// false
-// }
-// }
-
-// fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
-// self.push_to_nav_history(cx);
-// }
-
-// fn clone_on_split(
-// &self,
-// _workspace_id: WorkspaceId,
-// _: &mut ViewContext<Self>,
-// ) -> Option<Self>
-// where
-// Self: Sized,
-// {
-// Some(self.clone())
-// }
-
-// fn is_dirty(&self, _: &AppContext) -> bool {
-// self.is_dirty
-// }
-
-// fn has_conflict(&self, _: &AppContext) -> bool {
-// self.has_conflict
-// }
-
-// fn can_save(&self, cx: &AppContext) -> bool {
-// !self.project_items.is_empty()
-// && self
-// .project_items
-// .iter()
-// .all(|item| item.read(cx).entry_id.is_some())
-// }
-
-// fn save(
-// &mut self,
-// _: Model<Project>,
-// _: &mut ViewContext<Self>,
-// ) -> Task<anyhow::Result<()>> {
-// self.save_count += 1;
-// self.is_dirty = false;
-// Task::ready(Ok(()))
-// }
-
-// fn save_as(
-// &mut self,
-// _: Model<Project>,
-// _: std::path::PathBuf,
-// _: &mut ViewContext<Self>,
-// ) -> Task<anyhow::Result<()>> {
-// self.save_as_count += 1;
-// self.is_dirty = false;
-// Task::ready(Ok(()))
-// }
-
-// fn reload(
-// &mut self,
-// _: Model<Project>,
-// _: &mut ViewContext<Self>,
-// ) -> Task<anyhow::Result<()>> {
-// self.reload_count += 1;
-// self.is_dirty = false;
-// Task::ready(Ok(()))
-// }
-
-// fn to_item_events(_: &Self::Event) -> SmallVec<[ItemEvent; 2]> {
-// [ItemEvent::UpdateTab, ItemEvent::Edit].into()
-// }
-
-// fn serialized_item_kind() -> Option<&'static str> {
-// Some("TestItem")
-// }
-
-// fn deserialize(
-// _project: Model<Project>,
-// _workspace: WeakViewHandle<Workspace>,
-// workspace_id: WorkspaceId,
-// _item_id: ItemId,
-// cx: &mut ViewContext<Pane>,
-// ) -> Task<anyhow::Result<View<Self>>> {
-// let view = cx.add_view(|_cx| Self::new_deserialized(workspace_id));
-// Task::Ready(Some(anyhow::Ok(view)))
-// }
-// }
-// }
+#[cfg(any(test, feature = "test-support"))]
+pub mod test {
+ use super::{Item, ItemEvent};
+ use crate::{ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId};
+ use gpui::{
+ AnyElement, AppContext, Context as _, Div, EntityId, EventEmitter, FocusableView,
+ IntoElement, Model, Render, SharedString, Task, View, ViewContext, VisualContext, WeakView,
+ };
+ use project::{Project, ProjectEntryId, ProjectPath, WorktreeId};
+ use std::{any::Any, cell::Cell, path::Path};
+
+ pub struct TestProjectItem {
+ pub entry_id: Option<ProjectEntryId>,
+ pub project_path: Option<ProjectPath>,
+ }
+
+ pub struct TestItem {
+ pub workspace_id: WorkspaceId,
+ pub state: String,
+ pub label: String,
+ pub save_count: usize,
+ pub save_as_count: usize,
+ pub reload_count: usize,
+ pub is_dirty: bool,
+ pub is_singleton: bool,
+ pub has_conflict: bool,
+ pub project_items: Vec<Model<TestProjectItem>>,
+ pub nav_history: Option<ItemNavHistory>,
+ pub tab_descriptions: Option<Vec<&'static str>>,
+ pub tab_detail: Cell<Option<usize>>,
+ focus_handle: gpui::FocusHandle,
+ }
+
+ impl project::Item for TestProjectItem {
+ fn entry_id(&self, _: &AppContext) -> Option<ProjectEntryId> {
+ self.entry_id
+ }
+
+ fn project_path(&self, _: &AppContext) -> Option<ProjectPath> {
+ self.project_path.clone()
+ }
+ }
+
+ pub enum TestItemEvent {
+ Edit,
+ }
+
+ // impl Clone for TestItem {
+ // fn clone(&self) -> Self {
+ // Self {
+ // state: self.state.clone(),
+ // label: self.label.clone(),
+ // save_count: self.save_count,
+ // save_as_count: self.save_as_count,
+ // reload_count: self.reload_count,
+ // is_dirty: self.is_dirty,
+ // is_singleton: self.is_singleton,
+ // has_conflict: self.has_conflict,
+ // project_items: self.project_items.clone(),
+ // nav_history: None,
+ // tab_descriptions: None,
+ // tab_detail: Default::default(),
+ // workspace_id: self.workspace_id,
+ // focus_handle: self.focus_handle.clone(),
+ // }
+ // }
+ // }
+
+ impl TestProjectItem {
+ pub fn new(id: u64, path: &str, cx: &mut AppContext) -> Model<Self> {
+ let entry_id = Some(ProjectEntryId::from_proto(id));
+ let project_path = Some(ProjectPath {
+ worktree_id: WorktreeId::from_usize(0),
+ path: Path::new(path).into(),
+ });
+ cx.build_model(|_| Self {
+ entry_id,
+ project_path,
+ })
+ }
+
+ pub fn new_untitled(cx: &mut AppContext) -> Model<Self> {
+ cx.build_model(|_| Self {
+ project_path: None,
+ entry_id: None,
+ })
+ }
+ }
+
+ impl TestItem {
+ pub fn new(cx: &mut ViewContext<Self>) -> Self {
+ Self {
+ state: String::new(),
+ label: String::new(),
+ save_count: 0,
+ save_as_count: 0,
+ reload_count: 0,
+ is_dirty: false,
+ has_conflict: false,
+ project_items: Vec::new(),
+ is_singleton: true,
+ nav_history: None,
+ tab_descriptions: None,
+ tab_detail: Default::default(),
+ workspace_id: 0,
+ focus_handle: cx.focus_handle(),
+ }
+ }
+
+ pub fn new_deserialized(id: WorkspaceId, cx: &mut ViewContext<Self>) -> Self {
+ let mut this = Self::new(cx);
+ this.workspace_id = id;
+ this
+ }
+
+ pub fn with_label(mut self, state: &str) -> Self {
+ self.label = state.to_string();
+ self
+ }
+
+ pub fn with_singleton(mut self, singleton: bool) -> Self {
+ self.is_singleton = singleton;
+ self
+ }
+
+ pub fn with_dirty(mut self, dirty: bool) -> Self {
+ self.is_dirty = dirty;
+ self
+ }
+
+ pub fn with_conflict(mut self, has_conflict: bool) -> Self {
+ self.has_conflict = has_conflict;
+ self
+ }
+
+ pub fn with_project_items(mut self, items: &[Model<TestProjectItem>]) -> Self {
+ self.project_items.clear();
+ self.project_items.extend(items.iter().cloned());
+ self
+ }
+
+ pub fn set_state(&mut self, state: String, cx: &mut ViewContext<Self>) {
+ self.push_to_nav_history(cx);
+ self.state = state;
+ }
+
+ fn push_to_nav_history(&mut self, cx: &mut ViewContext<Self>) {
+ if let Some(history) = &mut self.nav_history {
+ history.push(Some(Box::new(self.state.clone())), cx);
+ }
+ }
+ }
+
+ impl Render for TestItem {
+ type Element = Div;
+
+ fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
+ gpui::div()
+ }
+ }
+
+ impl EventEmitter<ItemEvent> for TestItem {}
+
+ impl FocusableView for TestItem {
+ fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
+ self.focus_handle.clone()
+ }
+ }
+
+ impl Item for TestItem {
+ fn tab_description(&self, detail: usize, _: &AppContext) -> Option<SharedString> {
+ self.tab_descriptions.as_ref().and_then(|descriptions| {
+ let description = *descriptions.get(detail).or_else(|| descriptions.last())?;
+ Some(description.into())
+ })
+ }
+
+ fn tab_content(
+ &self,
+ detail: Option<usize>,
+ cx: &ui::prelude::WindowContext,
+ ) -> AnyElement {
+ self.tab_detail.set(detail);
+ gpui::div().into_any_element()
+ }
+
+ fn for_each_project_item(
+ &self,
+ cx: &AppContext,
+ f: &mut dyn FnMut(EntityId, &dyn project::Item),
+ ) {
+ self.project_items
+ .iter()
+ .for_each(|item| f(item.entity_id(), item.read(cx)))
+ }
+
+ fn is_singleton(&self, _: &AppContext) -> bool {
+ self.is_singleton
+ }
+
+ fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
+ self.nav_history = Some(history);
+ }
+
+ fn navigate(&mut self, state: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {
+ let state = *state.downcast::<String>().unwrap_or_default();
+ if state != self.state {
+ self.state = state;
+ true
+ } else {
+ false
+ }
+ }
+
+ fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
+ self.push_to_nav_history(cx);
+ }
+
+ fn clone_on_split(
+ &self,
+ _workspace_id: WorkspaceId,
+ cx: &mut ViewContext<Self>,
+ ) -> Option<View<Self>>
+ where
+ Self: Sized,
+ {
+ Some(cx.build_view(|cx| Self {
+ state: self.state.clone(),
+ label: self.label.clone(),
+ save_count: self.save_count,
+ save_as_count: self.save_as_count,
+ reload_count: self.reload_count,
+ is_dirty: self.is_dirty,
+ is_singleton: self.is_singleton,
+ has_conflict: self.has_conflict,
+ project_items: self.project_items.clone(),
+ nav_history: None,
+ tab_descriptions: None,
+ tab_detail: Default::default(),
+ workspace_id: self.workspace_id,
+ focus_handle: cx.focus_handle(),
+ }))
+ }
+
+ fn is_dirty(&self, _: &AppContext) -> bool {
+ self.is_dirty
+ }
+
+ fn has_conflict(&self, _: &AppContext) -> bool {
+ self.has_conflict
+ }
+
+ fn can_save(&self, cx: &AppContext) -> bool {
+ !self.project_items.is_empty()
+ && self
+ .project_items
+ .iter()
+ .all(|item| item.read(cx).entry_id.is_some())
+ }
+
+ fn save(
+ &mut self,
+ _: Model<Project>,
+ _: &mut ViewContext<Self>,
+ ) -> Task<anyhow::Result<()>> {
+ self.save_count += 1;
+ self.is_dirty = false;
+ Task::ready(Ok(()))
+ }
+
+ fn save_as(
+ &mut self,
+ _: Model<Project>,
+ _: std::path::PathBuf,
+ _: &mut ViewContext<Self>,
+ ) -> Task<anyhow::Result<()>> {
+ self.save_as_count += 1;
+ self.is_dirty = false;
+ Task::ready(Ok(()))
+ }
+
+ fn reload(
+ &mut self,
+ _: Model<Project>,
+ _: &mut ViewContext<Self>,
+ ) -> Task<anyhow::Result<()>> {
+ self.reload_count += 1;
+ self.is_dirty = false;
+ Task::ready(Ok(()))
+ }
+
+ fn serialized_item_kind() -> Option<&'static str> {
+ Some("TestItem")
+ }
+
+ fn deserialize(
+ _project: Model<Project>,
+ _workspace: WeakView<Workspace>,
+ workspace_id: WorkspaceId,
+ _item_id: ItemId,
+ cx: &mut ViewContext<Pane>,
+ ) -> Task<anyhow::Result<View<Self>>> {
+ let view = cx.build_view(|cx| Self::new_deserialized(workspace_id, cx));
+ Task::Ready(Some(anyhow::Ok(view)))
+ }
+ }
+}
@@ -16,7 +16,7 @@ mod workspace_settings;
use anyhow::{anyhow, Context as _, Result};
use async_trait::async_trait;
-use client2::{
+use client::{
proto::{self, PeerId},
Client, TypedEnvelope, User, UserStore,
};
@@ -37,7 +37,7 @@ use gpui::{
};
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools;
-use language2::{LanguageRegistry, Rope};
+use language::{LanguageRegistry, Rope};
use lazy_static::lazy_static;
pub use modal_layer::*;
use node_runtime::NodeRuntime;
@@ -49,9 +49,9 @@ pub use persistence::{
WorkspaceDb, DB,
};
use postage::stream::Stream;
-use project2::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};
+use project::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};
use serde::Deserialize;
-use settings2::Settings;
+use settings::Settings;
use status_bar::StatusBar;
pub use status_bar::StatusItemView;
use std::{
@@ -62,7 +62,7 @@ use std::{
sync::{atomic::AtomicUsize, Arc},
time::Duration,
};
-use theme2::{ActiveTheme, ThemeSettings};
+use theme::{ActiveTheme, ThemeSettings};
pub use toolbar::{ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
pub use ui;
use util::ResultExt;
@@ -301,7 +301,7 @@ pub struct AppState {
pub client: Arc<Client>,
pub user_store: Model<UserStore>,
pub workspace_store: Model<WorkspaceStore>,
- pub fs: Arc<dyn fs2::Fs>,
+ pub fs: Arc<dyn fs::Fs>,
pub call_factory: CallFactory,
pub build_window_options:
fn(Option<WindowBounds>, Option<Uuid>, &mut AppContext) -> WindowOptions,
@@ -312,7 +312,7 @@ pub struct WorkspaceStore {
workspaces: HashSet<WindowHandle<Workspace>>,
followers: Vec<Follower>,
client: Arc<Client>,
- _subscriptions: Vec<client2::Subscription>,
+ _subscriptions: Vec<client::Subscription>,
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
@@ -388,22 +388,22 @@ impl AppState {
#[cfg(any(test, feature = "test-support"))]
pub fn test(cx: &mut AppContext) -> Arc<Self> {
use node_runtime::FakeNodeRuntime;
- use settings2::SettingsStore;
+ use settings::SettingsStore;
if !cx.has_global::<SettingsStore>() {
let settings_store = SettingsStore::test(cx);
cx.set_global(settings_store);
}
- let fs = fs2::FakeFs::new(cx.background_executor().clone());
+ let fs = fs::FakeFs::new(cx.background_executor().clone());
let languages = Arc::new(LanguageRegistry::test());
let http_client = util::http::FakeHttpClient::with_404_response();
let client = Client::new(http_client.clone(), cx);
let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http_client, cx));
let workspace_store = cx.build_model(|cx| WorkspaceStore::new(client.clone(), cx));
- theme2::init(theme2::LoadThemes::JustBase, cx);
- client2::init(&client, cx);
+ theme::init(theme::LoadThemes::JustBase, cx);
+ client::init(&client, cx);
crate::init_settings(cx);
Arc::new(Self {
@@ -567,29 +567,29 @@ impl Workspace {
cx.observe(&project, |_, _, cx| cx.notify()).detach();
cx.subscribe(&project, move |this, _, event, cx| {
match event {
- project2::Event::RemoteIdChanged(_) => {
+ project::Event::RemoteIdChanged(_) => {
this.update_window_title(cx);
}
- project2::Event::CollaboratorLeft(peer_id) => {
+ project::Event::CollaboratorLeft(peer_id) => {
this.collaborator_left(*peer_id, cx);
}
- project2::Event::WorktreeRemoved(_) | project2::Event::WorktreeAdded => {
+ project::Event::WorktreeRemoved(_) | project::Event::WorktreeAdded => {
this.update_window_title(cx);
this.serialize_workspace(cx);
}
- project2::Event::DisconnectedFromHost => {
+ project::Event::DisconnectedFromHost => {
this.update_window_edited(cx);
cx.blur();
}
- project2::Event::Closed => {
+ project::Event::Closed => {
cx.remove_window();
}
- project2::Event::DeletedEntry(entry_id) => {
+ project::Event::DeletedEntry(entry_id) => {
for pane in this.panes.iter() {
pane.update(cx, |pane, cx| {
pane.handle_deleted_project_item(*entry_id, cx)
@@ -597,7 +597,7 @@ impl Workspace {
}
}
- project2::Event::Notification(message) => this.show_notification(0, cx, |cx| {
+ project::Event::Notification(message) => this.show_notification(0, cx, |cx| {
cx.build_view(|_| MessageNotification::new(message.clone()))
}),
@@ -1450,7 +1450,7 @@ impl Workspace {
.map(|entry| entry.id);
if let Some(entry_id) = entry_id {
workspace.project.update(cx, |_, cx| {
- cx.emit(project2::Event::ActiveEntryChanged(Some(entry_id)));
+ cx.emit(project::Event::ActiveEntryChanged(Some(entry_id)));
})
}
})
@@ -1812,8 +1812,7 @@ impl Workspace {
});
cx.subscribe(&pane, Self::handle_pane_event).detach();
self.panes.push(pane.clone());
- // todo!()
- // cx.focus(&pane);
+ cx.focus_view(&pane);
cx.emit(Event::PaneAdded(pane.clone()));
pane
}
@@ -1988,7 +1987,7 @@ impl Workspace {
where
T: ProjectItem,
{
- use project2::Item as _;
+ use project::Item as _;
let entry_id = project_item.read(cx).entry_id(cx);
if let Some(item) = entry_id
@@ -2013,7 +2012,7 @@ impl Workspace {
where
T: ProjectItem,
{
- use project2::Item as _;
+ use project::Item as _;
let entry_id = project_item.read(cx).entry_id(cx);
if let Some(item) = entry_id
@@ -2592,8 +2591,7 @@ impl Workspace {
title.push_str(" β");
}
- // todo!()
- // cx.set_window_title(&title);
+ cx.set_window_title(&title);
}
fn update_window_edited(&mut self, cx: &mut ViewContext<Self>) {
@@ -3673,7 +3671,7 @@ fn notify_if_database_failed(workspace: WindowHandle<Workspace>, cx: &mut AsyncA
workspace
.update(cx, |workspace, cx| {
- if (*db2::ALL_FILE_DB_FAILED).load(std::sync::atomic::Ordering::Acquire) {
+ if (*db::ALL_FILE_DB_FAILED).load(std::sync::atomic::Ordering::Acquire) {
workspace.show_notification_once(0, cx, |cx| {
cx.build_view(|_| {
MessageNotification::new("Failed to load the database file.")
@@ -4554,960 +4552,950 @@ fn parse_pixel_size_env_var(value: &str) -> Option<Size<GlobalPixels>> {
Some(size((width as f64).into(), (height as f64).into()))
}
-// #[cfg(test)]
-// mod tests {
-// use super::*;
-// use crate::{
-// dock::test::TestPanel,
-// item::test::{TestItem, TestItemEvent, TestProjectItem},
-// };
-// use fs::FakeFs;
-// use gpui::{executor::Deterministic, test::EmptyView, TestAppContext};
-// use project::{Project, ProjectEntryId};
-// use serde_json::json;
-// use settings::SettingsStore;
-// use std::{cell::RefCell, rc::Rc};
-
-// #[gpui::test]
-// async fn test_tab_disambiguation(cx: &mut TestAppContext) {
-// init_test(cx);
-
-// let fs = FakeFs::new(cx.background());
-// let project = Project::test(fs, [], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
-// let workspace = window.root(cx);
-
-// // Adding an item with no ambiguity renders the tab without detail.
-// let item1 = window.build_view(cx, |_| {
-// let mut item = TestItem::new();
-// item.tab_descriptions = Some(vec!["c", "b1/c", "a/b1/c"]);
-// item
-// });
-// workspace.update(cx, |workspace, cx| {
-// workspace.add_item(Box::new(item1.clone()), cx);
-// });
-// item1.read_with(cx, |item, _| assert_eq!(item.tab_detail.get(), None));
-
-// // Adding an item that creates ambiguity increases the level of detail on
-// // both tabs.
-// let item2 = window.build_view(cx, |_| {
-// let mut item = TestItem::new();
-// item.tab_descriptions = Some(vec!["c", "b2/c", "a/b2/c"]);
-// item
-// });
-// workspace.update(cx, |workspace, cx| {
-// workspace.add_item(Box::new(item2.clone()), cx);
-// });
-// item1.read_with(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(1)));
-// item2.read_with(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(1)));
-
-// // Adding an item that creates ambiguity increases the level of detail only
-// // on the ambiguous tabs. In this case, the ambiguity can't be resolved so
-// // we stop at the highest detail available.
-// let item3 = window.build_view(cx, |_| {
-// let mut item = TestItem::new();
-// item.tab_descriptions = Some(vec!["c", "b2/c", "a/b2/c"]);
-// item
-// });
-// workspace.update(cx, |workspace, cx| {
-// workspace.add_item(Box::new(item3.clone()), cx);
-// });
-// item1.read_with(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(1)));
-// item2.read_with(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(3)));
-// item3.read_with(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(3)));
-// }
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::item::{
+ test::{TestItem, TestProjectItem},
+ ItemEvent,
+ };
+ use fs::FakeFs;
+ use gpui::TestAppContext;
+ use project::{Project, ProjectEntryId};
+ use serde_json::json;
+ use settings::SettingsStore;
+ use std::{cell::RefCell, rc::Rc};
+
+ #[gpui::test]
+ async fn test_tab_disambiguation(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ let fs = FakeFs::new(cx.executor());
+ let project = Project::test(fs, [], cx).await;
+ let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
+
+ // Adding an item with no ambiguity renders the tab without detail.
+ let item1 = cx.build_view(|cx| {
+ let mut item = TestItem::new(cx);
+ item.tab_descriptions = Some(vec!["c", "b1/c", "a/b1/c"]);
+ item
+ });
+ workspace.update(cx, |workspace, cx| {
+ workspace.add_item(Box::new(item1.clone()), cx);
+ });
+ item1.update(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(0)));
+
+ // Adding an item that creates ambiguity increases the level of detail on
+ // both tabs.
+ let item2 = cx.build_view(|cx| {
+ let mut item = TestItem::new(cx);
+ item.tab_descriptions = Some(vec!["c", "b2/c", "a/b2/c"]);
+ item
+ });
+ workspace.update(cx, |workspace, cx| {
+ workspace.add_item(Box::new(item2.clone()), cx);
+ });
+ item1.update(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(1)));
+ item2.update(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(1)));
+
+ // Adding an item that creates ambiguity increases the level of detail only
+ // on the ambiguous tabs. In this case, the ambiguity can't be resolved so
+ // we stop at the highest detail available.
+ let item3 = cx.build_view(|cx| {
+ let mut item = TestItem::new(cx);
+ item.tab_descriptions = Some(vec!["c", "b2/c", "a/b2/c"]);
+ item
+ });
+ workspace.update(cx, |workspace, cx| {
+ workspace.add_item(Box::new(item3.clone()), cx);
+ });
+ item1.update(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(1)));
+ item2.update(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(3)));
+ item3.update(cx, |item, _| assert_eq!(item.tab_detail.get(), Some(3)));
+ }
-// #[gpui::test]
-// async fn test_tracking_active_path(cx: &mut TestAppContext) {
-// init_test(cx);
-
-// let fs = FakeFs::new(cx.background());
-// fs.insert_tree(
-// "/root1",
-// json!({
-// "one.txt": "",
-// "two.txt": "",
-// }),
-// )
-// .await;
-// fs.insert_tree(
-// "/root2",
-// json!({
-// "three.txt": "",
-// }),
-// )
-// .await;
+ #[gpui::test]
+ async fn test_tracking_active_path(cx: &mut TestAppContext) {
+ init_test(cx);
-// let project = Project::test(fs, ["root1".as_ref()], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
-// let workspace = window.root(cx);
-// let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
-// let worktree_id = project.read_with(cx, |project, cx| {
-// project.worktrees().next().unwrap().read(cx).id()
-// });
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(
+ "/root1",
+ json!({
+ "one.txt": "",
+ "two.txt": "",
+ }),
+ )
+ .await;
+ fs.insert_tree(
+ "/root2",
+ json!({
+ "three.txt": "",
+ }),
+ )
+ .await;
-// let item1 = window.build_view(cx, |cx| {
-// TestItem::new().with_project_items(&[TestProjectItem::new(1, "one.txt", cx)])
-// });
-// let item2 = window.build_view(cx, |cx| {
-// TestItem::new().with_project_items(&[TestProjectItem::new(2, "two.txt", cx)])
-// });
+ let project = Project::test(fs, ["root1".as_ref()], cx).await;
+ let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
+ let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
+ let worktree_id = project.read_with(cx, |project, cx| {
+ project.worktrees().next().unwrap().read(cx).id()
+ });
-// // Add an item to an empty pane
-// workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item1), cx));
-// project.read_with(cx, |project, cx| {
-// assert_eq!(
-// project.active_entry(),
-// project
-// .entry_for_path(&(worktree_id, "one.txt").into(), cx)
-// .map(|e| e.id)
-// );
-// });
-// assert_eq!(window.current_title(cx).as_deref(), Some("one.txt β root1"));
-
-// // Add a second item to a non-empty pane
-// workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx));
-// assert_eq!(window.current_title(cx).as_deref(), Some("two.txt β root1"));
-// project.read_with(cx, |project, cx| {
-// assert_eq!(
-// project.active_entry(),
-// project
-// .entry_for_path(&(worktree_id, "two.txt").into(), cx)
-// .map(|e| e.id)
-// );
-// });
+ let item1 = cx.build_view(|cx| {
+ TestItem::new(cx).with_project_items(&[TestProjectItem::new(1, "one.txt", cx)])
+ });
+ let item2 = cx.build_view(|cx| {
+ TestItem::new(cx).with_project_items(&[TestProjectItem::new(2, "two.txt", cx)])
+ });
-// // Close the active item
-// pane.update(cx, |pane, cx| {
-// pane.close_active_item(&Default::default(), cx).unwrap()
-// })
-// .await
-// .unwrap();
-// assert_eq!(window.current_title(cx).as_deref(), Some("one.txt β root1"));
-// project.read_with(cx, |project, cx| {
-// assert_eq!(
-// project.active_entry(),
-// project
-// .entry_for_path(&(worktree_id, "one.txt").into(), cx)
-// .map(|e| e.id)
-// );
-// });
+ // Add an item to an empty pane
+ workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item1), cx));
+ project.read_with(cx, |project, cx| {
+ assert_eq!(
+ project.active_entry(),
+ project
+ .entry_for_path(&(worktree_id, "one.txt").into(), cx)
+ .map(|e| e.id)
+ );
+ });
+ assert_eq!(cx.window_title().as_deref(), Some("one.txt β root1"));
+
+ // Add a second item to a non-empty pane
+ workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx));
+ assert_eq!(cx.window_title().as_deref(), Some("two.txt β root1"));
+ project.read_with(cx, |project, cx| {
+ assert_eq!(
+ project.active_entry(),
+ project
+ .entry_for_path(&(worktree_id, "two.txt").into(), cx)
+ .map(|e| e.id)
+ );
+ });
-// // Add a project folder
-// project
-// .update(cx, |project, cx| {
-// project.find_or_create_local_worktree("/root2", true, cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(
-// window.current_title(cx).as_deref(),
-// Some("one.txt β root1, root2")
-// );
-
-// // Remove a project folder
-// project.update(cx, |project, cx| project.remove_worktree(worktree_id, cx));
-// assert_eq!(window.current_title(cx).as_deref(), Some("one.txt β root2"));
-// }
+ // Close the active item
+ pane.update(cx, |pane, cx| {
+ pane.close_active_item(&Default::default(), cx).unwrap()
+ })
+ .await
+ .unwrap();
+ assert_eq!(cx.window_title().as_deref(), Some("one.txt β root1"));
+ project.read_with(cx, |project, cx| {
+ assert_eq!(
+ project.active_entry(),
+ project
+ .entry_for_path(&(worktree_id, "one.txt").into(), cx)
+ .map(|e| e.id)
+ );
+ });
-// #[gpui::test]
-// async fn test_close_window(cx: &mut TestAppContext) {
-// init_test(cx);
-
-// let fs = FakeFs::new(cx.background());
-// fs.insert_tree("/root", json!({ "one": "" })).await;
-
-// let project = Project::test(fs, ["root".as_ref()], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
-// let workspace = window.root(cx);
-
-// // When there are no dirty items, there's nothing to do.
-// let item1 = window.build_view(cx, |_| TestItem::new());
-// workspace.update(cx, |w, cx| w.add_item(Box::new(item1.clone()), cx));
-// let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx));
-// assert!(task.await.unwrap());
-
-// // When there are dirty untitled items, prompt to save each one. If the user
-// // cancels any prompt, then abort.
-// let item2 = window.build_view(cx, |_| TestItem::new().with_dirty(true));
-// let item3 = window.build_view(cx, |cx| {
-// TestItem::new()
-// .with_dirty(true)
-// .with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
-// });
-// workspace.update(cx, |w, cx| {
-// w.add_item(Box::new(item2.clone()), cx);
-// w.add_item(Box::new(item3.clone()), cx);
-// });
-// let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx));
-// cx.foreground().run_until_parked();
-// window.simulate_prompt_answer(2, cx); // cancel save all
-// cx.foreground().run_until_parked();
-// window.simulate_prompt_answer(2, cx); // cancel save all
-// cx.foreground().run_until_parked();
-// assert!(!window.has_pending_prompt(cx));
-// assert!(!task.await.unwrap());
-// }
+ // Add a project folder
+ project
+ .update(cx, |project, cx| {
+ project.find_or_create_local_worktree("/root2", true, cx)
+ })
+ .await
+ .unwrap();
+ assert_eq!(cx.window_title().as_deref(), Some("one.txt β root1, root2"));
-// #[gpui::test]
-// async fn test_close_pane_items(cx: &mut TestAppContext) {
-// init_test(cx);
+ // Remove a project folder
+ project.update(cx, |project, cx| project.remove_worktree(worktree_id, cx));
+ assert_eq!(cx.window_title().as_deref(), Some("one.txt β root2"));
+ }
-// let fs = FakeFs::new(cx.background());
+ #[gpui::test]
+ async fn test_close_window(cx: &mut TestAppContext) {
+ init_test(cx);
-// let project = Project::test(fs, None, cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree("/root", json!({ "one": "" })).await;
-// let item1 = window.build_view(cx, |cx| {
-// TestItem::new()
-// .with_dirty(true)
-// .with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
-// });
-// let item2 = window.build_view(cx, |cx| {
-// TestItem::new()
-// .with_dirty(true)
-// .with_conflict(true)
-// .with_project_items(&[TestProjectItem::new(2, "2.txt", cx)])
-// });
-// let item3 = window.build_view(cx, |cx| {
-// TestItem::new()
-// .with_dirty(true)
-// .with_conflict(true)
-// .with_project_items(&[TestProjectItem::new(3, "3.txt", cx)])
-// });
-// let item4 = window.build_view(cx, |cx| {
-// TestItem::new()
-// .with_dirty(true)
-// .with_project_items(&[TestProjectItem::new_untitled(cx)])
-// });
-// let pane = workspace.update(cx, |workspace, cx| {
-// workspace.add_item(Box::new(item1.clone()), cx);
-// workspace.add_item(Box::new(item2.clone()), cx);
-// workspace.add_item(Box::new(item3.clone()), cx);
-// workspace.add_item(Box::new(item4.clone()), cx);
-// workspace.active_pane().clone()
-// });
+ let project = Project::test(fs, ["root".as_ref()], cx).await;
+ let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
-// let close_items = pane.update(cx, |pane, cx| {
-// pane.activate_item(1, true, true, cx);
-// assert_eq!(pane.active_item().unwrap().id(), item2.id());
-// let item1_id = item1.id();
-// let item3_id = item3.id();
-// let item4_id = item4.id();
-// pane.close_items(cx, SaveIntent::Close, move |id| {
-// [item1_id, item3_id, item4_id].contains(&id)
-// })
-// });
-// cx.foreground().run_until_parked();
-
-// assert!(window.has_pending_prompt(cx));
-// // Ignore "Save all" prompt
-// window.simulate_prompt_answer(2, cx);
-// cx.foreground().run_until_parked();
-// // There's a prompt to save item 1.
-// pane.read_with(cx, |pane, _| {
-// assert_eq!(pane.items_len(), 4);
-// assert_eq!(pane.active_item().unwrap().id(), item1.id());
-// });
-// // Confirm saving item 1.
-// window.simulate_prompt_answer(0, cx);
-// cx.foreground().run_until_parked();
-
-// // Item 1 is saved. There's a prompt to save item 3.
-// pane.read_with(cx, |pane, cx| {
-// assert_eq!(item1.read(cx).save_count, 1);
-// assert_eq!(item1.read(cx).save_as_count, 0);
-// assert_eq!(item1.read(cx).reload_count, 0);
-// assert_eq!(pane.items_len(), 3);
-// assert_eq!(pane.active_item().unwrap().id(), item3.id());
-// });
-// assert!(window.has_pending_prompt(cx));
-
-// // Cancel saving item 3.
-// window.simulate_prompt_answer(1, cx);
-// cx.foreground().run_until_parked();
-
-// // Item 3 is reloaded. There's a prompt to save item 4.
-// pane.read_with(cx, |pane, cx| {
-// assert_eq!(item3.read(cx).save_count, 0);
-// assert_eq!(item3.read(cx).save_as_count, 0);
-// assert_eq!(item3.read(cx).reload_count, 1);
-// assert_eq!(pane.items_len(), 2);
-// assert_eq!(pane.active_item().unwrap().id(), item4.id());
-// });
-// assert!(window.has_pending_prompt(cx));
-
-// // Confirm saving item 4.
-// window.simulate_prompt_answer(0, cx);
-// cx.foreground().run_until_parked();
-
-// // There's a prompt for a path for item 4.
-// cx.simulate_new_path_selection(|_| Some(Default::default()));
-// close_items.await.unwrap();
-
-// // The requested items are closed.
-// pane.read_with(cx, |pane, cx| {
-// assert_eq!(item4.read(cx).save_count, 0);
-// assert_eq!(item4.read(cx).save_as_count, 1);
-// assert_eq!(item4.read(cx).reload_count, 0);
-// assert_eq!(pane.items_len(), 1);
-// assert_eq!(pane.active_item().unwrap().id(), item2.id());
-// });
-// }
+ // When there are no dirty items, there's nothing to do.
+ let item1 = cx.build_view(|cx| TestItem::new(cx));
+ workspace.update(cx, |w, cx| w.add_item(Box::new(item1.clone()), cx));
+ let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx));
+ assert!(task.await.unwrap());
-// #[gpui::test]
-// async fn test_prompting_to_save_only_on_last_item_for_entry(cx: &mut TestAppContext) {
-// init_test(cx);
-
-// let fs = FakeFs::new(cx.background());
-
-// let project = Project::test(fs, [], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-
-// // Create several workspace items with single project entries, and two
-// // workspace items with multiple project entries.
-// let single_entry_items = (0..=4)
-// .map(|project_entry_id| {
-// window.build_view(cx, |cx| {
-// TestItem::new()
-// .with_dirty(true)
-// .with_project_items(&[TestProjectItem::new(
-// project_entry_id,
-// &format!("{project_entry_id}.txt"),
-// cx,
-// )])
-// })
-// })
-// .collect::<Vec<_>>();
-// let item_2_3 = window.build_view(cx, |cx| {
-// TestItem::new()
-// .with_dirty(true)
-// .with_singleton(false)
-// .with_project_items(&[
-// single_entry_items[2].read(cx).project_items[0].clone(),
-// single_entry_items[3].read(cx).project_items[0].clone(),
-// ])
-// });
-// let item_3_4 = window.build_view(cx, |cx| {
-// TestItem::new()
-// .with_dirty(true)
-// .with_singleton(false)
-// .with_project_items(&[
-// single_entry_items[3].read(cx).project_items[0].clone(),
-// single_entry_items[4].read(cx).project_items[0].clone(),
-// ])
-// });
+ // When there are dirty untitled items, prompt to save each one. If the user
+ // cancels any prompt, then abort.
+ let item2 = cx.build_view(|cx| TestItem::new(cx).with_dirty(true));
+ let item3 = cx.build_view(|cx| {
+ TestItem::new(cx)
+ .with_dirty(true)
+ .with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
+ });
+ workspace.update(cx, |w, cx| {
+ w.add_item(Box::new(item2.clone()), cx);
+ w.add_item(Box::new(item3.clone()), cx);
+ });
+ let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx));
+ cx.executor().run_until_parked();
+ cx.simulate_prompt_answer(2); // cancel save all
+ cx.executor().run_until_parked();
+ cx.simulate_prompt_answer(2); // cancel save all
+ cx.executor().run_until_parked();
+ assert!(!cx.has_pending_prompt());
+ assert!(!task.await.unwrap());
+ }
-// // Create two panes that contain the following project entries:
-// // left pane:
-// // multi-entry items: (2, 3)
-// // single-entry items: 0, 1, 2, 3, 4
-// // right pane:
-// // single-entry items: 1
-// // multi-entry items: (3, 4)
-// let left_pane = workspace.update(cx, |workspace, cx| {
-// let left_pane = workspace.active_pane().clone();
-// workspace.add_item(Box::new(item_2_3.clone()), cx);
-// for item in single_entry_items {
-// workspace.add_item(Box::new(item), cx);
-// }
-// left_pane.update(cx, |pane, cx| {
-// pane.activate_item(2, true, true, cx);
-// });
+ #[gpui::test]
+ async fn test_close_pane_items(cx: &mut TestAppContext) {
+ init_test(cx);
-// workspace
-// .split_and_clone(left_pane.clone(), SplitDirection::Right, cx)
-// .unwrap();
+ let fs = FakeFs::new(cx.executor());
-// left_pane
-// });
+ let project = Project::test(fs, None, cx).await;
+ let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx));
-// //Need to cause an effect flush in order to respect new focus
-// workspace.update(cx, |workspace, cx| {
-// workspace.add_item(Box::new(item_3_4.clone()), cx);
-// cx.focus(&left_pane);
-// });
+ let item1 = cx.build_view(|cx| {
+ TestItem::new(cx)
+ .with_dirty(true)
+ .with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
+ });
+ let item2 = cx.build_view(|cx| {
+ TestItem::new(cx)
+ .with_dirty(true)
+ .with_conflict(true)
+ .with_project_items(&[TestProjectItem::new(2, "2.txt", cx)])
+ });
+ let item3 = cx.build_view(|cx| {
+ TestItem::new(cx)
+ .with_dirty(true)
+ .with_conflict(true)
+ .with_project_items(&[TestProjectItem::new(3, "3.txt", cx)])
+ });
+ let item4 = cx.build_view(|cx| {
+ TestItem::new(cx)
+ .with_dirty(true)
+ .with_project_items(&[TestProjectItem::new_untitled(cx)])
+ });
+ let pane = workspace.update(cx, |workspace, cx| {
+ workspace.add_item(Box::new(item1.clone()), cx);
+ workspace.add_item(Box::new(item2.clone()), cx);
+ workspace.add_item(Box::new(item3.clone()), cx);
+ workspace.add_item(Box::new(item4.clone()), cx);
+ workspace.active_pane().clone()
+ });
-// // When closing all of the items in the left pane, we should be prompted twice:
-// // once for project entry 0, and once for project entry 2. After those two
-// // prompts, the task should complete.
+ let close_items = pane.update(cx, |pane, cx| {
+ pane.activate_item(1, true, true, cx);
+ assert_eq!(pane.active_item().unwrap().item_id(), item2.item_id());
+ let item1_id = item1.item_id();
+ let item3_id = item3.item_id();
+ let item4_id = item4.item_id();
+ pane.close_items(cx, SaveIntent::Close, move |id| {
+ [item1_id, item3_id, item4_id].contains(&id)
+ })
+ });
+ cx.executor().run_until_parked();
+
+ assert!(cx.has_pending_prompt());
+ // Ignore "Save all" prompt
+ cx.simulate_prompt_answer(2);
+ cx.executor().run_until_parked();
+ // There's a prompt to save item 1.
+ pane.update(cx, |pane, _| {
+ assert_eq!(pane.items_len(), 4);
+ assert_eq!(pane.active_item().unwrap().item_id(), item1.item_id());
+ });
+ // Confirm saving item 1.
+ cx.simulate_prompt_answer(0);
+ cx.executor().run_until_parked();
+
+ // Item 1 is saved. There's a prompt to save item 3.
+ pane.update(cx, |pane, cx| {
+ assert_eq!(item1.read(cx).save_count, 1);
+ assert_eq!(item1.read(cx).save_as_count, 0);
+ assert_eq!(item1.read(cx).reload_count, 0);
+ assert_eq!(pane.items_len(), 3);
+ assert_eq!(pane.active_item().unwrap().item_id(), item3.item_id());
+ });
+ assert!(cx.has_pending_prompt());
+
+ // Cancel saving item 3.
+ cx.simulate_prompt_answer(1);
+ cx.executor().run_until_parked();
+
+ // Item 3 is reloaded. There's a prompt to save item 4.
+ pane.update(cx, |pane, cx| {
+ assert_eq!(item3.read(cx).save_count, 0);
+ assert_eq!(item3.read(cx).save_as_count, 0);
+ assert_eq!(item3.read(cx).reload_count, 1);
+ assert_eq!(pane.items_len(), 2);
+ assert_eq!(pane.active_item().unwrap().item_id(), item4.item_id());
+ });
+ assert!(cx.has_pending_prompt());
+
+ // Confirm saving item 4.
+ cx.simulate_prompt_answer(0);
+ cx.executor().run_until_parked();
+
+ // There's a prompt for a path for item 4.
+ cx.simulate_new_path_selection(|_| Some(Default::default()));
+ close_items.await.unwrap();
+
+ // The requested items are closed.
+ pane.update(cx, |pane, cx| {
+ assert_eq!(item4.read(cx).save_count, 0);
+ assert_eq!(item4.read(cx).save_as_count, 1);
+ assert_eq!(item4.read(cx).reload_count, 0);
+ assert_eq!(pane.items_len(), 1);
+ assert_eq!(pane.active_item().unwrap().item_id(), item2.item_id());
+ });
+ }
-// let close = left_pane.update(cx, |pane, cx| {
-// pane.close_items(cx, SaveIntent::Close, move |_| true)
-// });
-// cx.foreground().run_until_parked();
-// // Discard "Save all" prompt
-// window.simulate_prompt_answer(2, cx);
-
-// cx.foreground().run_until_parked();
-// left_pane.read_with(cx, |pane, cx| {
-// assert_eq!(
-// pane.active_item().unwrap().project_entry_ids(cx).as_slice(),
-// &[ProjectEntryId::from_proto(0)]
-// );
-// });
-// window.simulate_prompt_answer(0, cx);
+ #[gpui::test]
+ async fn test_prompting_to_save_only_on_last_item_for_entry(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ let fs = FakeFs::new(cx.executor());
+ let project = Project::test(fs, [], cx).await;
+ let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx));
+
+ // Create several workspace items with single project entries, and two
+ // workspace items with multiple project entries.
+ let single_entry_items = (0..=4)
+ .map(|project_entry_id| {
+ cx.build_view(|cx| {
+ TestItem::new(cx)
+ .with_dirty(true)
+ .with_project_items(&[TestProjectItem::new(
+ project_entry_id,
+ &format!("{project_entry_id}.txt"),
+ cx,
+ )])
+ })
+ })
+ .collect::<Vec<_>>();
+ let item_2_3 = cx.build_view(|cx| {
+ TestItem::new(cx)
+ .with_dirty(true)
+ .with_singleton(false)
+ .with_project_items(&[
+ single_entry_items[2].read(cx).project_items[0].clone(),
+ single_entry_items[3].read(cx).project_items[0].clone(),
+ ])
+ });
+ let item_3_4 = cx.build_view(|cx| {
+ TestItem::new(cx)
+ .with_dirty(true)
+ .with_singleton(false)
+ .with_project_items(&[
+ single_entry_items[3].read(cx).project_items[0].clone(),
+ single_entry_items[4].read(cx).project_items[0].clone(),
+ ])
+ });
-// cx.foreground().run_until_parked();
-// left_pane.read_with(cx, |pane, cx| {
-// assert_eq!(
-// pane.active_item().unwrap().project_entry_ids(cx).as_slice(),
-// &[ProjectEntryId::from_proto(2)]
-// );
-// });
-// window.simulate_prompt_answer(0, cx);
+ // Create two panes that contain the following project entries:
+ // left pane:
+ // multi-entry items: (2, 3)
+ // single-entry items: 0, 1, 2, 3, 4
+ // right pane:
+ // single-entry items: 1
+ // multi-entry items: (3, 4)
+ let left_pane = workspace.update(cx, |workspace, cx| {
+ let left_pane = workspace.active_pane().clone();
+ workspace.add_item(Box::new(item_2_3.clone()), cx);
+ for item in single_entry_items {
+ workspace.add_item(Box::new(item), cx);
+ }
+ left_pane.update(cx, |pane, cx| {
+ pane.activate_item(2, true, true, cx);
+ });
-// cx.foreground().run_until_parked();
-// close.await.unwrap();
-// left_pane.read_with(cx, |pane, _| {
-// assert_eq!(pane.items_len(), 0);
-// });
-// }
+ let right_pane = workspace
+ .split_and_clone(left_pane.clone(), SplitDirection::Right, cx)
+ .unwrap();
-// #[gpui::test]
-// async fn test_autosave(deterministic: Arc<Deterministic>, cx: &mut gpui::TestAppContext) {
-// init_test(cx);
+ right_pane.update(cx, |pane, cx| {
+ pane.add_item(Box::new(item_3_4.clone()), true, true, None, cx);
+ });
-// let fs = FakeFs::new(cx.background());
+ left_pane
+ });
-// let project = Project::test(fs, [], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-// let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
+ cx.focus_view(&left_pane);
-// let item = window.build_view(cx, |cx| {
-// TestItem::new().with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
-// });
-// let item_id = item.id();
-// workspace.update(cx, |workspace, cx| {
-// workspace.add_item(Box::new(item.clone()), cx);
-// });
+ // When closing all of the items in the left pane, we should be prompted twice:
+ // once for project entry 0, and once for project entry 2. Project entries 1,
+ // 3, and 4 are all still open in the other paten. After those two
+ // prompts, the task should complete.
-// // Autosave on window change.
-// item.update(cx, |item, cx| {
-// cx.update_global(|settings: &mut SettingsStore, cx| {
-// settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
-// settings.autosave = Some(AutosaveSetting::OnWindowChange);
-// })
-// });
-// item.is_dirty = true;
-// });
+ let close = left_pane.update(cx, |pane, cx| {
+ pane.close_all_items(&CloseAllItems::default(), cx).unwrap()
+ });
+ cx.executor().run_until_parked();
-// // Deactivating the window saves the file.
-// window.simulate_deactivation(cx);
-// deterministic.run_until_parked();
-// item.read_with(cx, |item, _| assert_eq!(item.save_count, 1));
-
-// // Autosave on focus change.
-// item.update(cx, |item, cx| {
-// cx.focus_self();
-// cx.update_global(|settings: &mut SettingsStore, cx| {
-// settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
-// settings.autosave = Some(AutosaveSetting::OnFocusChange);
-// })
-// });
-// item.is_dirty = true;
-// });
+ // Discard "Save all" prompt
+ cx.simulate_prompt_answer(2);
-// // Blurring the item saves the file.
-// item.update(cx, |_, cx| cx.blur());
-// deterministic.run_until_parked();
-// item.read_with(cx, |item, _| assert_eq!(item.save_count, 2));
+ cx.executor().run_until_parked();
+ left_pane.update(cx, |pane, cx| {
+ assert_eq!(
+ pane.active_item().unwrap().project_entry_ids(cx).as_slice(),
+ &[ProjectEntryId::from_proto(0)]
+ );
+ });
+ cx.simulate_prompt_answer(0);
-// // Deactivating the window still saves the file.
-// window.simulate_activation(cx);
-// item.update(cx, |item, cx| {
-// cx.focus_self();
-// item.is_dirty = true;
-// });
-// window.simulate_deactivation(cx);
+ cx.executor().run_until_parked();
+ left_pane.update(cx, |pane, cx| {
+ assert_eq!(
+ pane.active_item().unwrap().project_entry_ids(cx).as_slice(),
+ &[ProjectEntryId::from_proto(2)]
+ );
+ });
+ cx.simulate_prompt_answer(0);
-// deterministic.run_until_parked();
-// item.read_with(cx, |item, _| assert_eq!(item.save_count, 3));
+ cx.executor().run_until_parked();
+ close.await.unwrap();
+ left_pane.update(cx, |pane, _| {
+ assert_eq!(pane.items_len(), 0);
+ });
+ }
-// // Autosave after delay.
-// item.update(cx, |item, cx| {
-// cx.update_global(|settings: &mut SettingsStore, cx| {
-// settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
-// settings.autosave = Some(AutosaveSetting::AfterDelay { milliseconds: 500 });
-// })
-// });
-// item.is_dirty = true;
-// cx.emit(TestItemEvent::Edit);
-// });
+ #[gpui::test]
+ async fn test_autosave(cx: &mut gpui::TestAppContext) {
+ init_test(cx);
-// // Delay hasn't fully expired, so the file is still dirty and unsaved.
-// deterministic.advance_clock(Duration::from_millis(250));
-// item.read_with(cx, |item, _| assert_eq!(item.save_count, 3));
+ let fs = FakeFs::new(cx.executor());
+ let project = Project::test(fs, [], cx).await;
+ let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx));
+ let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
-// // After delay expires, the file is saved.
-// deterministic.advance_clock(Duration::from_millis(250));
-// item.read_with(cx, |item, _| assert_eq!(item.save_count, 4));
+ let item = cx.build_view(|cx| {
+ TestItem::new(cx).with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
+ });
+ let item_id = item.entity_id();
+ workspace.update(cx, |workspace, cx| {
+ workspace.add_item(Box::new(item.clone()), cx);
+ });
-// // Autosave on focus change, ensuring closing the tab counts as such.
-// item.update(cx, |item, cx| {
-// cx.update_global(|settings: &mut SettingsStore, cx| {
-// settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
-// settings.autosave = Some(AutosaveSetting::OnFocusChange);
-// })
-// });
-// item.is_dirty = true;
-// });
+ // Autosave on window change.
+ item.update(cx, |item, cx| {
+ cx.update_global(|settings: &mut SettingsStore, cx| {
+ settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
+ settings.autosave = Some(AutosaveSetting::OnWindowChange);
+ })
+ });
+ item.is_dirty = true;
+ });
-// pane.update(cx, |pane, cx| {
-// pane.close_items(cx, SaveIntent::Close, move |id| id == item_id)
-// })
-// .await
-// .unwrap();
-// assert!(!window.has_pending_prompt(cx));
-// item.read_with(cx, |item, _| assert_eq!(item.save_count, 5));
-
-// // Add the item again, ensuring autosave is prevented if the underlying file has been deleted.
-// workspace.update(cx, |workspace, cx| {
-// workspace.add_item(Box::new(item.clone()), cx);
-// });
-// item.update(cx, |item, cx| {
-// item.project_items[0].update(cx, |item, _| {
-// item.entry_id = None;
-// });
-// item.is_dirty = true;
-// cx.blur();
-// });
-// deterministic.run_until_parked();
-// item.read_with(cx, |item, _| assert_eq!(item.save_count, 5));
+ // Deactivating the window saves the file.
+ cx.simulate_deactivation();
+ cx.executor().run_until_parked();
+ item.update(cx, |item, _| assert_eq!(item.save_count, 1));
+
+ // Autosave on focus change.
+ item.update(cx, |item, cx| {
+ cx.focus_self();
+ cx.update_global(|settings: &mut SettingsStore, cx| {
+ settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
+ settings.autosave = Some(AutosaveSetting::OnFocusChange);
+ })
+ });
+ item.is_dirty = true;
+ });
-// // Ensure autosave is prevented for deleted files also when closing the buffer.
-// let _close_items = pane.update(cx, |pane, cx| {
-// pane.close_items(cx, SaveIntent::Close, move |id| id == item_id)
-// });
-// deterministic.run_until_parked();
-// assert!(window.has_pending_prompt(cx));
-// item.read_with(cx, |item, _| assert_eq!(item.save_count, 5));
-// }
+ // Blurring the item saves the file.
+ item.update(cx, |_, cx| cx.blur());
+ cx.executor().run_until_parked();
+ item.update(cx, |item, _| assert_eq!(item.save_count, 2));
-// #[gpui::test]
-// async fn test_pane_navigation(cx: &mut gpui::TestAppContext) {
-// init_test(cx);
+ // Deactivating the window still saves the file.
+ cx.simulate_activation();
+ item.update(cx, |item, cx| {
+ cx.focus_self();
+ item.is_dirty = true;
+ });
+ cx.simulate_deactivation();
-// let fs = FakeFs::new(cx.background());
+ cx.executor().run_until_parked();
+ item.update(cx, |item, _| assert_eq!(item.save_count, 3));
-// let project = Project::test(fs, [], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
+ // Autosave after delay.
+ item.update(cx, |item, cx| {
+ cx.update_global(|settings: &mut SettingsStore, cx| {
+ settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
+ settings.autosave = Some(AutosaveSetting::AfterDelay { milliseconds: 500 });
+ })
+ });
+ item.is_dirty = true;
+ cx.emit(ItemEvent::Edit);
+ });
-// let item = window.build_view(cx, |cx| {
-// TestItem::new().with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
-// });
-// let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
-// let toolbar = pane.read_with(cx, |pane, _| pane.toolbar().clone());
-// let toolbar_notify_count = Rc::new(RefCell::new(0));
-
-// workspace.update(cx, |workspace, cx| {
-// workspace.add_item(Box::new(item.clone()), cx);
-// let toolbar_notification_count = toolbar_notify_count.clone();
-// cx.observe(&toolbar, move |_, _, _| {
-// *toolbar_notification_count.borrow_mut() += 1
-// })
-// .detach();
-// });
+ // Delay hasn't fully expired, so the file is still dirty and unsaved.
+ cx.executor().advance_clock(Duration::from_millis(250));
+ item.update(cx, |item, _| assert_eq!(item.save_count, 3));
-// pane.read_with(cx, |pane, _| {
-// assert!(!pane.can_navigate_backward());
-// assert!(!pane.can_navigate_forward());
-// });
+ // After delay expires, the file is saved.
+ cx.executor().advance_clock(Duration::from_millis(250));
+ item.update(cx, |item, _| assert_eq!(item.save_count, 4));
-// item.update(cx, |item, cx| {
-// item.set_state("one".to_string(), cx);
-// });
+ // Autosave on focus change, ensuring closing the tab counts as such.
+ item.update(cx, |item, cx| {
+ cx.update_global(|settings: &mut SettingsStore, cx| {
+ settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
+ settings.autosave = Some(AutosaveSetting::OnFocusChange);
+ })
+ });
+ item.is_dirty = true;
+ });
-// // Toolbar must be notified to re-render the navigation buttons
-// assert_eq!(*toolbar_notify_count.borrow(), 1);
+ pane.update(cx, |pane, cx| {
+ pane.close_items(cx, SaveIntent::Close, move |id| id == item_id)
+ })
+ .await
+ .unwrap();
+ assert!(!cx.has_pending_prompt());
+ item.update(cx, |item, _| assert_eq!(item.save_count, 5));
+
+ // Add the item again, ensuring autosave is prevented if the underlying file has been deleted.
+ workspace.update(cx, |workspace, cx| {
+ workspace.add_item(Box::new(item.clone()), cx);
+ });
+ item.update(cx, |item, cx| {
+ item.project_items[0].update(cx, |item, _| {
+ item.entry_id = None;
+ });
+ item.is_dirty = true;
+ cx.blur();
+ });
+ cx.executor().run_until_parked();
+ item.update(cx, |item, _| assert_eq!(item.save_count, 5));
-// pane.read_with(cx, |pane, _| {
-// assert!(pane.can_navigate_backward());
-// assert!(!pane.can_navigate_forward());
-// });
+ // Ensure autosave is prevented for deleted files also when closing the buffer.
+ let _close_items = pane.update(cx, |pane, cx| {
+ pane.close_items(cx, SaveIntent::Close, move |id| id == item_id)
+ });
+ cx.executor().run_until_parked();
+ assert!(cx.has_pending_prompt());
+ item.update(cx, |item, _| assert_eq!(item.save_count, 5));
+ }
-// workspace
-// .update(cx, |workspace, cx| workspace.go_back(pane.downgrade(), cx))
-// .await
-// .unwrap();
+ #[gpui::test]
+ async fn test_pane_navigation(cx: &mut gpui::TestAppContext) {
+ init_test(cx);
-// assert_eq!(*toolbar_notify_count.borrow(), 3);
-// pane.read_with(cx, |pane, _| {
-// assert!(!pane.can_navigate_backward());
-// assert!(pane.can_navigate_forward());
-// });
-// }
+ let fs = FakeFs::new(cx.executor());
-// #[gpui::test]
-// async fn test_toggle_docks_and_panels(cx: &mut gpui::TestAppContext) {
-// init_test(cx);
-// let fs = FakeFs::new(cx.background());
+ let project = Project::test(fs, [], cx).await;
+ let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx));
-// let project = Project::test(fs, [], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
+ let item = cx.build_view(|cx| {
+ TestItem::new(cx).with_project_items(&[TestProjectItem::new(1, "1.txt", cx)])
+ });
+ let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
+ let toolbar = pane.update(cx, |pane, _| pane.toolbar().clone());
+ let toolbar_notify_count = Rc::new(RefCell::new(0));
+
+ workspace.update(cx, |workspace, cx| {
+ workspace.add_item(Box::new(item.clone()), cx);
+ let toolbar_notification_count = toolbar_notify_count.clone();
+ cx.observe(&toolbar, move |_, _, _| {
+ *toolbar_notification_count.borrow_mut() += 1
+ })
+ .detach();
+ });
-// let panel = workspace.update(cx, |workspace, cx| {
-// let panel = cx.build_view(|_| TestPanel::new(DockPosition::Right));
-// workspace.add_panel(panel.clone(), cx);
+ pane.update(cx, |pane, _| {
+ assert!(!pane.can_navigate_backward());
+ assert!(!pane.can_navigate_forward());
+ });
-// workspace
-// .right_dock()
-// .update(cx, |right_dock, cx| right_dock.set_open(true, cx));
+ item.update(cx, |item, cx| {
+ item.set_state("one".to_string(), cx);
+ });
-// panel
-// });
+ // Toolbar must be notified to re-render the navigation buttons
+ assert_eq!(*toolbar_notify_count.borrow(), 1);
-// let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
-// pane.update(cx, |pane, cx| {
-// let item = cx.build_view(|_| TestItem::new());
-// pane.add_item(Box::new(item), true, true, None, cx);
-// });
+ pane.update(cx, |pane, _| {
+ assert!(pane.can_navigate_backward());
+ assert!(!pane.can_navigate_forward());
+ });
-// // Transfer focus from center to panel
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_panel_focus::<TestPanel>(cx);
-// });
+ workspace
+ .update(cx, |workspace, cx| workspace.go_back(pane.downgrade(), cx))
+ .await
+ .unwrap();
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(workspace.right_dock().read(cx).is_open());
-// assert!(!panel.is_zoomed(cx));
-// assert!(panel.has_focus(cx));
-// });
+ assert_eq!(*toolbar_notify_count.borrow(), 2);
+ pane.update(cx, |pane, _| {
+ assert!(!pane.can_navigate_backward());
+ assert!(pane.can_navigate_forward());
+ });
+ }
-// // Transfer focus from panel to center
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_panel_focus::<TestPanel>(cx);
-// });
+ // #[gpui::test]
+ // async fn test_toggle_docks_and_panels(cx: &mut gpui::TestAppContext) {
+ // init_test(cx);
+ // let fs = FakeFs::new(cx.executor());
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(workspace.right_dock().read(cx).is_open());
-// assert!(!panel.is_zoomed(cx));
-// assert!(!panel.has_focus(cx));
-// });
+ // let project = Project::test(fs, [], cx).await;
+ // let window = cx.add_window(|cx| Workspace::test_new(project, cx));
+ // let workspace = window.root(cx);
-// // Close the dock
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_dock(DockPosition::Right, cx);
-// });
+ // let panel = workspace.update(cx, |workspace, cx| {
+ // let panel = cx.build_view(|_| TestPanel::new(DockPosition::Right));
+ // workspace.add_panel(panel.clone(), cx);
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(!workspace.right_dock().read(cx).is_open());
-// assert!(!panel.is_zoomed(cx));
-// assert!(!panel.has_focus(cx));
-// });
+ // workspace
+ // .right_dock()
+ // .update(cx, |right_dock, cx| right_dock.set_open(true, cx));
-// // Open the dock
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_dock(DockPosition::Right, cx);
-// });
+ // panel
+ // });
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(workspace.right_dock().read(cx).is_open());
-// assert!(!panel.is_zoomed(cx));
-// assert!(panel.has_focus(cx));
-// });
+ // let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
+ // pane.update(cx, |pane, cx| {
+ // let item = cx.build_view(|_| TestItem::new(cx));
+ // pane.add_item(Box::new(item), true, true, None, cx);
+ // });
-// // Focus and zoom panel
-// panel.update(cx, |panel, cx| {
-// cx.focus_self();
-// panel.set_zoomed(true, cx)
-// });
+ // // Transfer focus from center to panel
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_panel_focus::<TestPanel>(cx);
+ // });
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(workspace.right_dock().read(cx).is_open());
-// assert!(panel.is_zoomed(cx));
-// assert!(panel.has_focus(cx));
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(workspace.right_dock().read(cx).is_open());
+ // assert!(!panel.is_zoomed(cx));
+ // assert!(panel.has_focus(cx));
+ // });
-// // Transfer focus to the center closes the dock
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_panel_focus::<TestPanel>(cx);
-// });
+ // // Transfer focus from panel to center
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_panel_focus::<TestPanel>(cx);
+ // });
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(!workspace.right_dock().read(cx).is_open());
-// assert!(panel.is_zoomed(cx));
-// assert!(!panel.has_focus(cx));
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(workspace.right_dock().read(cx).is_open());
+ // assert!(!panel.is_zoomed(cx));
+ // assert!(!panel.has_focus(cx));
+ // });
-// // Transferring focus back to the panel keeps it zoomed
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_panel_focus::<TestPanel>(cx);
-// });
+ // // Close the dock
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_dock(DockPosition::Right, cx);
+ // });
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(workspace.right_dock().read(cx).is_open());
-// assert!(panel.is_zoomed(cx));
-// assert!(panel.has_focus(cx));
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(!workspace.right_dock().read(cx).is_open());
+ // assert!(!panel.is_zoomed(cx));
+ // assert!(!panel.has_focus(cx));
+ // });
-// // Close the dock while it is zoomed
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_dock(DockPosition::Right, cx)
-// });
+ // // Open the dock
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_dock(DockPosition::Right, cx);
+ // });
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(!workspace.right_dock().read(cx).is_open());
-// assert!(panel.is_zoomed(cx));
-// assert!(workspace.zoomed.is_none());
-// assert!(!panel.has_focus(cx));
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(workspace.right_dock().read(cx).is_open());
+ // assert!(!panel.is_zoomed(cx));
+ // assert!(panel.has_focus(cx));
+ // });
-// // Opening the dock, when it's zoomed, retains focus
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_dock(DockPosition::Right, cx)
-// });
+ // // Focus and zoom panel
+ // panel.update(cx, |panel, cx| {
+ // cx.focus_self();
+ // panel.set_zoomed(true, cx)
+ // });
-// workspace.read_with(cx, |workspace, cx| {
-// assert!(workspace.right_dock().read(cx).is_open());
-// assert!(panel.is_zoomed(cx));
-// assert!(workspace.zoomed.is_some());
-// assert!(panel.has_focus(cx));
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(workspace.right_dock().read(cx).is_open());
+ // assert!(panel.is_zoomed(cx));
+ // assert!(panel.has_focus(cx));
+ // });
-// // Unzoom and close the panel, zoom the active pane.
-// panel.update(cx, |panel, cx| panel.set_zoomed(false, cx));
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_dock(DockPosition::Right, cx)
-// });
-// pane.update(cx, |pane, cx| pane.toggle_zoom(&Default::default(), cx));
+ // // Transfer focus to the center closes the dock
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_panel_focus::<TestPanel>(cx);
+ // });
-// // Opening a dock unzooms the pane.
-// workspace.update(cx, |workspace, cx| {
-// workspace.toggle_dock(DockPosition::Right, cx)
-// });
-// workspace.read_with(cx, |workspace, cx| {
-// let pane = pane.read(cx);
-// assert!(!pane.is_zoomed());
-// assert!(!pane.has_focus());
-// assert!(workspace.right_dock().read(cx).is_open());
-// assert!(workspace.zoomed.is_none());
-// });
-// }
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(!workspace.right_dock().read(cx).is_open());
+ // assert!(panel.is_zoomed(cx));
+ // assert!(!panel.has_focus(cx));
+ // });
-// #[gpui::test]
-// async fn test_panels(cx: &mut gpui::TestAppContext) {
-// init_test(cx);
-// let fs = FakeFs::new(cx.background());
-
-// let project = Project::test(fs, [], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-
-// let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| {
-// // Add panel_1 on the left, panel_2 on the right.
-// let panel_1 = cx.build_view(|_| TestPanel::new(DockPosition::Left));
-// workspace.add_panel(panel_1.clone(), cx);
-// workspace
-// .left_dock()
-// .update(cx, |left_dock, cx| left_dock.set_open(true, cx));
-// let panel_2 = cx.build_view(|_| TestPanel::new(DockPosition::Right));
-// workspace.add_panel(panel_2.clone(), cx);
-// workspace
-// .right_dock()
-// .update(cx, |right_dock, cx| right_dock.set_open(true, cx));
-
-// let left_dock = workspace.left_dock();
-// assert_eq!(
-// left_dock.read(cx).visible_panel().unwrap().id(),
-// panel_1.id()
-// );
-// assert_eq!(
-// left_dock.read(cx).active_panel_size(cx).unwrap(),
-// panel_1.size(cx)
-// );
+ // // Transferring focus back to the panel keeps it zoomed
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_panel_focus::<TestPanel>(cx);
+ // });
-// left_dock.update(cx, |left_dock, cx| {
-// left_dock.resize_active_panel(Some(1337.), cx)
-// });
-// assert_eq!(
-// workspace
-// .right_dock()
-// .read(cx)
-// .visible_panel()
-// .unwrap()
-// .id(),
-// panel_2.id()
-// );
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(workspace.right_dock().read(cx).is_open());
+ // assert!(panel.is_zoomed(cx));
+ // assert!(panel.has_focus(cx));
+ // });
-// (panel_1, panel_2)
-// });
+ // // Close the dock while it is zoomed
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_dock(DockPosition::Right, cx)
+ // });
-// // Move panel_1 to the right
-// panel_1.update(cx, |panel_1, cx| {
-// panel_1.set_position(DockPosition::Right, cx)
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(!workspace.right_dock().read(cx).is_open());
+ // assert!(panel.is_zoomed(cx));
+ // assert!(workspace.zoomed.is_none());
+ // assert!(!panel.has_focus(cx));
+ // });
-// workspace.update(cx, |workspace, cx| {
-// // Since panel_1 was visible on the left, it should now be visible now that it's been moved to the right.
-// // Since it was the only panel on the left, the left dock should now be closed.
-// assert!(!workspace.left_dock().read(cx).is_open());
-// assert!(workspace.left_dock().read(cx).visible_panel().is_none());
-// let right_dock = workspace.right_dock();
-// assert_eq!(
-// right_dock.read(cx).visible_panel().unwrap().id(),
-// panel_1.id()
-// );
-// assert_eq!(right_dock.read(cx).active_panel_size(cx).unwrap(), 1337.);
+ // // Opening the dock, when it's zoomed, retains focus
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_dock(DockPosition::Right, cx)
+ // });
-// // Now we move panel_2Β to the left
-// panel_2.set_position(DockPosition::Left, cx);
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // assert!(workspace.right_dock().read(cx).is_open());
+ // assert!(panel.is_zoomed(cx));
+ // assert!(workspace.zoomed.is_some());
+ // assert!(panel.has_focus(cx));
+ // });
-// workspace.update(cx, |workspace, cx| {
-// // Since panel_2 was not visible on the right, we don't open the left dock.
-// assert!(!workspace.left_dock().read(cx).is_open());
-// // And the right dock is unaffected in it's displaying of panel_1
-// assert!(workspace.right_dock().read(cx).is_open());
-// assert_eq!(
-// workspace
-// .right_dock()
-// .read(cx)
-// .visible_panel()
-// .unwrap()
-// .id(),
-// panel_1.id()
-// );
-// });
+ // // Unzoom and close the panel, zoom the active pane.
+ // panel.update(cx, |panel, cx| panel.set_zoomed(false, cx));
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_dock(DockPosition::Right, cx)
+ // });
+ // pane.update(cx, |pane, cx| pane.toggle_zoom(&Default::default(), cx));
-// // Move panel_1 back to the left
-// panel_1.update(cx, |panel_1, cx| {
-// panel_1.set_position(DockPosition::Left, cx)
-// });
+ // // Opening a dock unzooms the pane.
+ // workspace.update(cx, |workspace, cx| {
+ // workspace.toggle_dock(DockPosition::Right, cx)
+ // });
+ // workspace.update(cx, |workspace, cx| {
+ // let pane = pane.read(cx);
+ // assert!(!pane.is_zoomed());
+ // assert!(!pane.has_focus());
+ // assert!(workspace.right_dock().read(cx).is_open());
+ // assert!(workspace.zoomed.is_none());
+ // });
+ // }
-// workspace.update(cx, |workspace, cx| {
-// // Since panel_1 was visible on the right, we open the left dock and make panel_1 active.
-// let left_dock = workspace.left_dock();
-// assert!(left_dock.read(cx).is_open());
-// assert_eq!(
-// left_dock.read(cx).visible_panel().unwrap().id(),
-// panel_1.id()
-// );
-// assert_eq!(left_dock.read(cx).active_panel_size(cx).unwrap(), 1337.);
-// // And right the dock should be closed as it no longer has any panels.
-// assert!(!workspace.right_dock().read(cx).is_open());
+ // #[gpui::test]
+ // async fn test_panels(cx: &mut gpui::TestAppContext) {
+ // init_test(cx);
+ // let fs = FakeFs::new(cx.executor());
+
+ // let project = Project::test(fs, [], cx).await;
+ // let window = cx.add_window(|cx| Workspace::test_new(project, cx));
+ // let workspace = window.root(cx);
+
+ // let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| {
+ // // Add panel_1 on the left, panel_2 on the right.
+ // let panel_1 = cx.build_view(|_| TestPanel::new(DockPosition::Left));
+ // workspace.add_panel(panel_1.clone(), cx);
+ // workspace
+ // .left_dock()
+ // .update(cx, |left_dock, cx| left_dock.set_open(true, cx));
+ // let panel_2 = cx.build_view(|_| TestPanel::new(DockPosition::Right));
+ // workspace.add_panel(panel_2.clone(), cx);
+ // workspace
+ // .right_dock()
+ // .update(cx, |right_dock, cx| right_dock.set_open(true, cx));
+
+ // let left_dock = workspace.left_dock();
+ // assert_eq!(
+ // left_dock.read(cx).visible_panel().unwrap().id(),
+ // panel_1.id()
+ // );
+ // assert_eq!(
+ // left_dock.read(cx).active_panel_size(cx).unwrap(),
+ // panel_1.size(cx)
+ // );
+
+ // left_dock.update(cx, |left_dock, cx| {
+ // left_dock.resize_active_panel(Some(1337.), cx)
+ // });
+ // assert_eq!(
+ // workspace
+ // .right_dock()
+ // .read(cx)
+ // .visible_panel()
+ // .unwrap()
+ // .id(),
+ // panel_2.id()
+ // );
+
+ // (panel_1, panel_2)
+ // });
-// // Now we move panel_1 to the bottom
-// panel_1.set_position(DockPosition::Bottom, cx);
-// });
+ // // Move panel_1 to the right
+ // panel_1.update(cx, |panel_1, cx| {
+ // panel_1.set_position(DockPosition::Right, cx)
+ // });
-// workspace.update(cx, |workspace, cx| {
-// // Since panel_1 was visible on the left, we close the left dock.
-// assert!(!workspace.left_dock().read(cx).is_open());
-// // The bottom dock is sized based on the panel's default size,
-// // since the panel orientation changed from vertical to horizontal.
-// let bottom_dock = workspace.bottom_dock();
-// assert_eq!(
-// bottom_dock.read(cx).active_panel_size(cx).unwrap(),
-// panel_1.size(cx),
-// );
-// // Close bottom dock and move panel_1 back to the left.
-// bottom_dock.update(cx, |bottom_dock, cx| bottom_dock.set_open(false, cx));
-// panel_1.set_position(DockPosition::Left, cx);
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // // Since panel_1 was visible on the left, it should now be visible now that it's been moved to the right.
+ // // Since it was the only panel on the left, the left dock should now be closed.
+ // assert!(!workspace.left_dock().read(cx).is_open());
+ // assert!(workspace.left_dock().read(cx).visible_panel().is_none());
+ // let right_dock = workspace.right_dock();
+ // assert_eq!(
+ // right_dock.read(cx).visible_panel().unwrap().id(),
+ // panel_1.id()
+ // );
+ // assert_eq!(right_dock.read(cx).active_panel_size(cx).unwrap(), 1337.);
+
+ // // Now we move panel_2Β to the left
+ // panel_2.set_position(DockPosition::Left, cx);
+ // });
-// // Emit activated event on panel 1
-// panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Activated));
+ // workspace.update(cx, |workspace, cx| {
+ // // Since panel_2 was not visible on the right, we don't open the left dock.
+ // assert!(!workspace.left_dock().read(cx).is_open());
+ // // And the right dock is unaffected in it's displaying of panel_1
+ // assert!(workspace.right_dock().read(cx).is_open());
+ // assert_eq!(
+ // workspace
+ // .right_dock()
+ // .read(cx)
+ // .visible_panel()
+ // .unwrap()
+ // .id(),
+ // panel_1.id()
+ // );
+ // });
-// // Now the left dock is open and panel_1 is active and focused.
-// workspace.read_with(cx, |workspace, cx| {
-// let left_dock = workspace.left_dock();
-// assert!(left_dock.read(cx).is_open());
-// assert_eq!(
-// left_dock.read(cx).visible_panel().unwrap().id(),
-// panel_1.id()
-// );
-// assert!(panel_1.is_focused(cx));
-// });
+ // // Move panel_1 back to the left
+ // panel_1.update(cx, |panel_1, cx| {
+ // panel_1.set_position(DockPosition::Left, cx)
+ // });
-// // Emit closed event on panel 2, which is not active
-// panel_2.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed));
+ // workspace.update(cx, |workspace, cx| {
+ // // Since panel_1 was visible on the right, we open the left dock and make panel_1 active.
+ // let left_dock = workspace.left_dock();
+ // assert!(left_dock.read(cx).is_open());
+ // assert_eq!(
+ // left_dock.read(cx).visible_panel().unwrap().id(),
+ // panel_1.id()
+ // );
+ // assert_eq!(left_dock.read(cx).active_panel_size(cx).unwrap(), 1337.);
+ // // And right the dock should be closed as it no longer has any panels.
+ // assert!(!workspace.right_dock().read(cx).is_open());
+
+ // // Now we move panel_1 to the bottom
+ // panel_1.set_position(DockPosition::Bottom, cx);
+ // });
-// // Wo don't close the left dock, because panel_2 wasn't the active panel
-// workspace.read_with(cx, |workspace, cx| {
-// let left_dock = workspace.left_dock();
-// assert!(left_dock.read(cx).is_open());
-// assert_eq!(
-// left_dock.read(cx).visible_panel().unwrap().id(),
-// panel_1.id()
-// );
-// });
+ // workspace.update(cx, |workspace, cx| {
+ // // Since panel_1 was visible on the left, we close the left dock.
+ // assert!(!workspace.left_dock().read(cx).is_open());
+ // // The bottom dock is sized based on the panel's default size,
+ // // since the panel orientation changed from vertical to horizontal.
+ // let bottom_dock = workspace.bottom_dock();
+ // assert_eq!(
+ // bottom_dock.read(cx).active_panel_size(cx).unwrap(),
+ // panel_1.size(cx),
+ // );
+ // // Close bottom dock and move panel_1 back to the left.
+ // bottom_dock.update(cx, |bottom_dock, cx| bottom_dock.set_open(false, cx));
+ // panel_1.set_position(DockPosition::Left, cx);
+ // });
-// // Emitting a ZoomIn event shows the panel as zoomed.
-// panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomIn));
-// workspace.read_with(cx, |workspace, _| {
-// assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
-// assert_eq!(workspace.zoomed_position, Some(DockPosition::Left));
-// });
+ // // Emit activated event on panel 1
+ // panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Activated));
+
+ // // Now the left dock is open and panel_1 is active and focused.
+ // workspace.update(cx, |workspace, cx| {
+ // let left_dock = workspace.left_dock();
+ // assert!(left_dock.read(cx).is_open());
+ // assert_eq!(
+ // left_dock.read(cx).visible_panel().unwrap().id(),
+ // panel_1.id()
+ // );
+ // assert!(panel_1.is_focused(cx));
+ // });
-// // Move panel to another dock while it is zoomed
-// panel_1.update(cx, |panel, cx| panel.set_position(DockPosition::Right, cx));
-// workspace.read_with(cx, |workspace, _| {
-// assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
-// assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
-// });
+ // // Emit closed event on panel 2, which is not active
+ // panel_2.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed));
+
+ // // Wo don't close the left dock, because panel_2 wasn't the active panel
+ // workspace.update(cx, |workspace, cx| {
+ // let left_dock = workspace.left_dock();
+ // assert!(left_dock.read(cx).is_open());
+ // assert_eq!(
+ // left_dock.read(cx).visible_panel().unwrap().id(),
+ // panel_1.id()
+ // );
+ // });
-// // If focus is transferred to another view that's not a panel or another pane, we still show
-// // the panel as zoomed.
-// let focus_receiver = window.build_view(cx, |_| EmptyView);
-// focus_receiver.update(cx, |_, cx| cx.focus_self());
-// workspace.read_with(cx, |workspace, _| {
-// assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
-// assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
-// });
+ // // Emitting a ZoomIn event shows the panel as zoomed.
+ // panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomIn));
+ // workspace.update(cx, |workspace, _| {
+ // assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
+ // assert_eq!(workspace.zoomed_position, Some(DockPosition::Left));
+ // });
-// // If focus is transferred elsewhere in the workspace, the panel is no longer zoomed.
-// workspace.update(cx, |_, cx| cx.focus_self());
-// workspace.read_with(cx, |workspace, _| {
-// assert_eq!(workspace.zoomed, None);
-// assert_eq!(workspace.zoomed_position, None);
-// });
+ // // Move panel to another dock while it is zoomed
+ // panel_1.update(cx, |panel, cx| panel.set_position(DockPosition::Right, cx));
+ // workspace.update(cx, |workspace, _| {
+ // assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
+ // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
+ // });
-// // If focus is transferred again to another view that's not a panel or a pane, we won't
-// // show the panel as zoomed because it wasn't zoomed before.
-// focus_receiver.update(cx, |_, cx| cx.focus_self());
-// workspace.read_with(cx, |workspace, _| {
-// assert_eq!(workspace.zoomed, None);
-// assert_eq!(workspace.zoomed_position, None);
-// });
+ // // If focus is transferred to another view that's not a panel or another pane, we still show
+ // // the panel as zoomed.
+ // let focus_receiver = cx.build_view(|_| EmptyView);
+ // focus_receiver.update(cx, |_, cx| cx.focus_self());
+ // workspace.update(cx, |workspace, _| {
+ // assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
+ // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
+ // });
-// // When focus is transferred back to the panel, it is zoomed again.
-// panel_1.update(cx, |_, cx| cx.focus_self());
-// workspace.read_with(cx, |workspace, _| {
-// assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
-// assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
-// });
+ // // If focus is transferred elsewhere in the workspace, the panel is no longer zoomed.
+ // workspace.update(cx, |_, cx| cx.focus_self());
+ // workspace.update(cx, |workspace, _| {
+ // assert_eq!(workspace.zoomed, None);
+ // assert_eq!(workspace.zoomed_position, None);
+ // });
-// // Emitting a ZoomOut event unzooms the panel.
-// panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomOut));
-// workspace.read_with(cx, |workspace, _| {
-// assert_eq!(workspace.zoomed, None);
-// assert_eq!(workspace.zoomed_position, None);
-// });
+ // // If focus is transferred again to another view that's not a panel or a pane, we won't
+ // // show the panel as zoomed because it wasn't zoomed before.
+ // focus_receiver.update(cx, |_, cx| cx.focus_self());
+ // workspace.update(cx, |workspace, _| {
+ // assert_eq!(workspace.zoomed, None);
+ // assert_eq!(workspace.zoomed_position, None);
+ // });
-// // Emit closed event on panel 1, which is active
-// panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed));
+ // // When focus is transferred back to the panel, it is zoomed again.
+ // panel_1.update(cx, |_, cx| cx.focus_self());
+ // workspace.update(cx, |workspace, _| {
+ // assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any()));
+ // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
+ // });
-// // Now the left dock is closed, because panel_1 was the active panel
-// workspace.read_with(cx, |workspace, cx| {
-// let right_dock = workspace.right_dock();
-// assert!(!right_dock.read(cx).is_open());
-// });
-// }
+ // // Emitting a ZoomOut event unzooms the panel.
+ // panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomOut));
+ // workspace.update(cx, |workspace, _| {
+ // assert_eq!(workspace.zoomed, None);
+ // assert_eq!(workspace.zoomed_position, None);
+ // });
-// pub fn init_test(cx: &mut TestAppContext) {
-// cx.foreground().forbid_parking();
-// cx.update(|cx| {
-// cx.set_global(SettingsStore::test(cx));
-// theme::init((), cx);
-// language::init(cx);
-// crate::init_settings(cx);
-// Project::init_settings(cx);
-// });
-// }
-// }
+ // // Emit closed event on panel 1, which is active
+ // panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed));
+
+ // // Now the left dock is closed, because panel_1 was the active panel
+ // workspace.update(cx, |workspace, cx| {
+ // let right_dock = workspace.right_dock();
+ // assert!(!right_dock.read(cx).is_open());
+ // });
+ // }
+
+ pub fn init_test(cx: &mut TestAppContext) {
+ cx.update(|cx| {
+ let settings_store = SettingsStore::test(cx);
+ cx.set_global(settings_store);
+ theme::init(theme::LoadThemes::JustBase, cx);
+ language::init(cx);
+ crate::init_settings(cx);
+ Project::init_settings(cx);
+ });
+ }
+}