Detailed changes
@@ -14,7 +14,7 @@ pub use test_context::*;
use crate::{
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle,
- AppMetadata, AssetSource, ClipboardItem, Context, DispatchPhase, DisplayId, Executor,
+ AppMetadata, AssetSource, ClipboardItem, Context, DispatchPhase, DisplayId, Entity, Executor,
FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly,
Pixels, Platform, Point, Render, SharedString, SubscriberSet, Subscription, SvgRenderer, Task,
TextStyle, TextStyleRefinement, TextSystem, View, ViewContext, Window, WindowContext,
@@ -694,13 +694,17 @@ impl AppContext {
self.globals_by_type.insert(global_type, lease.global);
}
- pub fn observe_release<E: 'static>(
+ pub fn observe_release<E, T>(
&mut self,
- handle: &Model<E>,
- mut on_release: impl FnMut(&mut E, &mut AppContext) + Send + 'static,
- ) -> Subscription {
+ handle: &E,
+ mut on_release: impl FnMut(&mut T, &mut AppContext) + Send + 'static,
+ ) -> Subscription
+ where
+ E: Entity<T>,
+ T: 'static,
+ {
self.release_listeners.insert(
- handle.entity_id,
+ handle.entity_id(),
Box::new(move |entity, cx| {
let entity = entity.downcast_mut().expect("invalid entity type");
on_release(entity, cx)
@@ -314,7 +314,7 @@ impl AnyView {
.map_err(|_| self)
}
- pub(crate) fn entity_type(&self) -> TypeId {
+ pub fn entity_type(&self) -> TypeId {
self.0.entity_type()
}
@@ -1,88 +1,80 @@
-// use crate::{
-// pane, persistence::model::ItemId, searchable::SearchableItemHandle, FollowableItemBuilders,
-// ItemNavHistory, Pane, ToolbarItemLocation, ViewId, Workspace, WorkspaceId,
-// };
-// use crate::{AutosaveSetting, DelayedDebouncedEditAction, WorkspaceSettings};
+use crate::{
+ pane::{self, Pane},
+ persistence::model::ItemId,
+ searchable::SearchableItemHandle,
+ workspace_settings::{AutosaveSetting, WorkspaceSettings},
+ DelayedDebouncedEditAction, FollowableItemBuilders, ItemNavHistory, ToolbarItemLocation,
+ ViewId, Workspace, WorkspaceId,
+};
use anyhow::Result;
use client2::{
proto::{self, PeerId},
Client,
};
+use gpui2::{
+ AnyElement, AnyView, AppContext, EventEmitter, HighlightStyle, Model, Pixels, Point, Render,
+ SharedString, Task, View, ViewContext, WeakView, WindowContext,
+};
+use parking_lot::Mutex;
+use project2::{Project, ProjectEntryId, ProjectPath};
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
use settings2::Settings;
+use smallvec::SmallVec;
+use std::{
+ any::{Any, TypeId},
+ ops::Range,
+ path::PathBuf,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+ time::Duration,
+};
use theme2::Theme;
-// use client2::{
-// proto::{self, PeerId},
-// Client,
-// };
-// use gpui2::geometry::vector::Vector2F;
-// use gpui2::AnyWindowHandle;
-// use gpui2::{
-// fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, Model, Task, View,
-// ViewContext, View, WeakViewHandle, WindowContext,
-// };
-// use project2::{Project, ProjectEntryId, ProjectPath};
-// use schemars::JsonSchema;
-// use serde_derive::{Deserialize, Serialize};
-// use settings2::Setting;
-// use smallvec::SmallVec;
-// use std::{
-// any::{Any, TypeId},
-// borrow::Cow,
-// cell::RefCell,
-// fmt,
-// ops::Range,
-// path::PathBuf,
-// rc::Rc,
-// sync::{
-// atomic::{AtomicBool, Ordering},
-// Arc,
-// },
-// time::Duration,
-// };
-// use theme2::Theme;
-
-// #[derive(Deserialize)]
-// pub struct ItemSettings {
-// pub git_status: bool,
-// pub close_position: ClosePosition,
-// }
-// #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-// #[serde(rename_all = "lowercase")]
-// pub enum ClosePosition {
-// Left,
-// #[default]
-// Right,
-// }
+#[derive(Deserialize)]
+pub struct ItemSettings {
+ pub git_status: bool,
+ pub close_position: ClosePosition,
+}
-// impl ClosePosition {
-// pub fn right(&self) -> bool {
-// match self {
-// ClosePosition::Left => false,
-// ClosePosition::Right => true,
-// }
-// }
-// }
+#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "lowercase")]
+pub enum ClosePosition {
+ Left,
+ #[default]
+ Right,
+}
-// #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-// pub struct ItemSettingsContent {
-// git_status: Option<bool>,
-// close_position: Option<ClosePosition>,
-// }
+impl ClosePosition {
+ pub fn right(&self) -> bool {
+ match self {
+ ClosePosition::Left => false,
+ ClosePosition::Right => true,
+ }
+ }
+}
-// impl Setting for ItemSettings {
-// const KEY: Option<&'static str> = Some("tabs");
+#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+pub struct ItemSettingsContent {
+ git_status: Option<bool>,
+ close_position: Option<ClosePosition>,
+}
-// type FileContent = ItemSettingsContent;
+impl Settings for ItemSettings {
+ const KEY: Option<&'static str> = Some("tabs");
-// fn load(
-// default_value: &Self::FileContent,
-// user_values: &[&Self::FileContent],
-// _: &gpui2::AppContext,
-// ) -> anyhow::Result<Self> {
-// Self::load_via_json_merge(default_value, user_values)
-// }
-// }
+ type FileContent = ItemSettingsContent;
+
+ fn load(
+ default_value: &Self::FileContent,
+ user_values: &[&Self::FileContent],
+ _: &mut AppContext,
+ ) -> Result<Self> {
+ Self::load_via_json_merge(default_value, user_values)
+ }
+}
#[derive(Eq, PartialEq, Hash, Debug)]
pub enum ItemEvent {
@@ -165,18 +157,18 @@ pub trait Item: Render + EventEmitter + Send {
false
}
- // fn act_as_type<'a>(
- // &'a self,
- // type_id: TypeId,
- // self_handle: &'a View<Self>,
- // _: &'a AppContext,
- // ) -> Option<&AnyViewHandle> {
- // if TypeId::of::<Self>() == type_id {
- // Some(self_handle)
- // } else {
- // None
- // }
- // }
+ fn act_as_type<'a>(
+ &'a self,
+ type_id: TypeId,
+ self_handle: &'a View<Self>,
+ _: &'a AppContext,
+ ) -> Option<AnyView> {
+ if TypeId::of::<Self>() == type_id {
+ Some(self_handle.clone().into_any())
+ } else {
+ None
+ }
+ }
fn as_searchable(&self, _: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
None
@@ -215,35 +207,6 @@ pub trait Item: Render + EventEmitter + Send {
}
}
-use std::{
- any::Any,
- cell::RefCell,
- ops::Range,
- path::PathBuf,
- rc::Rc,
- sync::{
- atomic::{AtomicBool, Ordering},
- Arc,
- },
- time::Duration,
-};
-
-use gpui2::{
- AnyElement, AnyView, AnyWindowHandle, AppContext, EventEmitter, HighlightStyle, Model, Pixels,
- Point, Render, SharedString, Task, View, ViewContext, WeakView, WindowContext,
-};
-use project2::{Project, ProjectEntryId, ProjectPath};
-use smallvec::SmallVec;
-
-use crate::{
- pane::{self, Pane},
- persistence::model::ItemId,
- searchable::SearchableItemHandle,
- workspace_settings::{AutosaveSetting, WorkspaceSettings},
- DelayedDebouncedEditAction, FollowableItemBuilders, ItemNavHistory, ToolbarItemLocation,
- ViewId, Workspace, WorkspaceId,
-};
-
pub trait ItemHandle: 'static + Send {
fn subscribe_to_item_events(
&self,
@@ -275,7 +238,6 @@ pub trait ItemHandle: 'static + Send {
fn workspace_deactivated(&self, cx: &mut WindowContext);
fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool;
fn id(&self) -> usize;
- fn window(&self) -> AnyWindowHandle;
fn to_any(&self) -> AnyView;
fn is_dirty(&self, cx: &AppContext) -> bool;
fn has_conflict(&self, cx: &AppContext) -> bool;
@@ -288,12 +250,12 @@ pub trait ItemHandle: 'static + Send {
cx: &mut WindowContext,
) -> Task<Result<()>>;
fn reload(&self, project: Model<Project>, cx: &mut WindowContext) -> Task<Result<()>>;
- // fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle>; todo!()
+ fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option<AnyView>;
fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>>;
fn on_release(
&self,
cx: &mut AppContext,
- callback: Box<dyn FnOnce(&mut AppContext)>,
+ callback: Box<dyn FnOnce(&mut AppContext) + Send>,
) -> gpui2::Subscription;
fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>>;
fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation;
@@ -303,23 +265,21 @@ pub trait ItemHandle: 'static + Send {
fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Point<Pixels>>;
}
-pub trait WeakItemHandle: Send {
+pub trait WeakItemHandle: Send + Sync {
fn id(&self) -> usize;
- fn window(&self) -> AnyWindowHandle;
fn upgrade(&self) -> Option<Box<dyn ItemHandle>>;
}
-// todo!()
-// impl dyn ItemHandle {
-// pub fn downcast<T: View>(&self) -> Option<View<T>> {
-// self.as_any().clone().downcast()
-// }
+impl dyn ItemHandle {
+ pub fn downcast<V: 'static>(&self) -> Option<View<V>> {
+ self.to_any().downcast().ok()
+ }
-// pub fn act_as<T: View>(&self, cx: &AppContext) -> Option<View<T>> {
-// self.act_as_type(TypeId::of::<T>(), cx)
-// .and_then(|t| t.clone().downcast())
-// }
-// }
+ pub fn act_as<V: 'static>(&self, cx: &AppContext) -> Option<View<V>> {
+ self.act_as_type(TypeId::of::<V>(), cx)
+ .and_then(|t| t.downcast().ok())
+ }
+}
impl<T: Item> ItemHandle for View<T> {
fn subscribe_to_item_events(
@@ -438,8 +398,8 @@ impl<T: Item> ItemHandle for View<T> {
.is_none()
{
let mut pending_autosave = DelayedDebouncedEditAction::new();
- let pending_update = Rc::new(RefCell::new(None));
- let pending_update_scheduled = Rc::new(AtomicBool::new(false));
+ let pending_update = Arc::new(Mutex::new(None));
+ let pending_update_scheduled = Arc::new(AtomicBool::new(false));
let mut event_subscription =
Some(cx.subscribe(self, move |workspace, item, event, cx| {
@@ -462,33 +422,31 @@ impl<T: Item> ItemHandle for View<T> {
workspace.unfollow(&pane, cx);
}
- if item.add_event_to_update_proto(
- event,
- &mut *pending_update.borrow_mut(),
- cx,
- ) && !pending_update_scheduled.load(Ordering::SeqCst)
+ if item.add_event_to_update_proto(event, &mut *pending_update.lock(), cx)
+ && !pending_update_scheduled.load(Ordering::SeqCst)
{
pending_update_scheduled.store(true, Ordering::SeqCst);
- cx.after_window_update({
- let pending_update = pending_update.clone();
- let pending_update_scheduled = pending_update_scheduled.clone();
- move |this, cx| {
- pending_update_scheduled.store(false, Ordering::SeqCst);
- this.update_followers(
- is_project_item,
- proto::update_followers::Variant::UpdateView(
- proto::UpdateView {
- id: item
- .remote_id(&this.app_state.client, cx)
- .map(|id| id.to_proto()),
- variant: pending_update.borrow_mut().take(),
- leader_id,
- },
- ),
- cx,
- );
- }
- });
+ todo!("replace with on_next_frame?");
+ // cx.after_window_update({
+ // let pending_update = pending_update.clone();
+ // let pending_update_scheduled = pending_update_scheduled.clone();
+ // move |this, cx| {
+ // pending_update_scheduled.store(false, Ordering::SeqCst);
+ // this.update_followers(
+ // is_project_item,
+ // proto::update_followers::Variant::UpdateView(
+ // proto::UpdateView {
+ // id: item
+ // .remote_id(&this.app_state.client, cx)
+ // .map(|id| id.to_proto()),
+ // variant: pending_update.borrow_mut().take(),
+ // leader_id,
+ // },
+ // ),
+ // cx,
+ // );
+ // }
+ // });
}
}
@@ -525,15 +483,16 @@ impl<T: Item> ItemHandle for View<T> {
}
}));
- 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();
+ todo!("observe focus");
+ // 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();
let item_id = self.id();
cx.observe_release(self, move |workspace, _, _| {
@@ -564,11 +523,6 @@ impl<T: Item> ItemHandle for View<T> {
self.id()
}
- fn window(&self) -> AnyWindowHandle {
- todo!()
- // AnyViewHandle::window(self)
- }
-
fn to_any(&self) -> AnyView {
self.clone().into_any()
}
@@ -602,16 +556,15 @@ impl<T: Item> ItemHandle for View<T> {
self.update(cx, |item, cx| item.reload(project, cx))
}
- // todo!()
- // fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle> {
- // self.read(cx).act_as_type(type_id, self, cx)
- // }
+ fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<AnyView> {
+ self.read(cx).act_as_type(type_id, self, cx)
+ }
fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>> {
if cx.has_global::<FollowableItemBuilders>() {
let builders = cx.global::<FollowableItemBuilders>();
- let item = self.as_any();
- Some(builders.get(&item.view_type())?.1(item))
+ let item = self.to_any();
+ Some(builders.get(&item.entity_type())?.1(&item))
} else {
None
}
@@ -620,7 +573,7 @@ impl<T: Item> ItemHandle for View<T> {
fn on_release(
&self,
cx: &mut AppContext,
- callback: Box<dyn FnOnce(&mut AppContext)>,
+ callback: Box<dyn FnOnce(&mut AppContext) + Send>,
) -> gpui2::Subscription {
cx.observe_release(self, move |_, cx| callback(cx))
}
@@ -673,10 +626,6 @@ impl<T: Item> WeakItemHandle for WeakView<T> {
self.id()
}
- fn window(&self) -> AnyWindowHandle {
- self.window()
- }
-
fn upgrade(&self) -> Option<Box<dyn ItemHandle>> {
self.upgrade().map(|v| Box::new(v) as Box<dyn ItemHandle>)
}
@@ -2,10 +2,15 @@
use crate::{
item::{Item, ItemHandle, WeakItemHandle},
+ toolbar::Toolbar,
SplitDirection, Workspace,
};
+use anyhow::Result;
use collections::{HashMap, VecDeque};
-use gpui2::{EventEmitter, Model, View, ViewContext, WeakView};
+use gpui2::{
+ AppContext, EventEmitter, Model, Task, View, ViewContext, VisualContext, WeakView,
+ WindowContext,
+};
use parking_lot::Mutex;
use project2::{Project, ProjectEntryId, ProjectPath};
use serde::Deserialize;
@@ -68,6 +73,7 @@ pub enum SaveIntent {
// pub save_intent: Option<SaveIntent>,
// }
+// todo!()
// actions!(
// pane,
// [
@@ -90,8 +96,9 @@ pub enum SaveIntent {
// impl_actions!(pane, [ActivateItem, CloseActiveItem, CloseAllItems]);
-// const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
+const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
+// todo!()
// pub fn init(cx: &mut AppContext) {
// cx.add_action(Pane::toggle_zoom);
// cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| {
@@ -330,7 +337,7 @@ impl Pane {
pane: handle.clone(),
next_timestamp,
}))),
- // toolbar: cx.add_view(|_| Toolbar::new()),
+ toolbar: cx.build_view(|_| Toolbar::new()),
// tab_bar_context_menu: TabBarContextMenu {
// kind: TabBarContextMenuKind::New,
// handle: context_menu,
@@ -447,33 +454,33 @@ impl Pane {
}
}
- // pub fn nav_history(&self) -> &NavHistory {
- // &self.nav_history
- // }
+ pub fn nav_history(&self) -> &NavHistory {
+ &self.nav_history
+ }
- // pub fn nav_history_mut(&mut self) -> &mut NavHistory {
- // &mut self.nav_history
- // }
+ pub fn nav_history_mut(&mut self) -> &mut NavHistory {
+ &mut self.nav_history
+ }
- // pub fn disable_history(&mut self) {
- // self.nav_history.disable();
- // }
+ pub fn disable_history(&mut self) {
+ self.nav_history.disable();
+ }
- // pub fn enable_history(&mut self) {
- // self.nav_history.enable();
- // }
+ pub fn enable_history(&mut self) {
+ self.nav_history.enable();
+ }
- // pub fn can_navigate_backward(&self) -> bool {
- // !self.nav_history.0.borrow().backward_stack.is_empty()
- // }
+ pub fn can_navigate_backward(&self) -> bool {
+ !self.nav_history.0.lock().backward_stack.is_empty()
+ }
- // pub fn can_navigate_forward(&self) -> bool {
- // !self.nav_history.0.borrow().forward_stack.is_empty()
- // }
+ pub fn can_navigate_forward(&self) -> bool {
+ !self.nav_history.0.lock().forward_stack.is_empty()
+ }
- // fn history_updated(&mut self, cx: &mut ViewContext<Self>) {
- // self.toolbar.update(cx, |_, cx| cx.notify());
- // }
+ fn history_updated(&mut self, cx: &mut ViewContext<Self>) {
+ self.toolbar.update(cx, |_, cx| cx.notify());
+ }
pub(crate) fn open_item(
&mut self,
@@ -736,115 +743,115 @@ impl Pane {
// ))
// }
- // pub fn close_item_by_id(
- // &mut self,
- // item_id_to_close: usize,
- // save_intent: SaveIntent,
- // cx: &mut ViewContext<Self>,
- // ) -> Task<Result<()>> {
- // self.close_items(cx, save_intent, move |view_id| view_id == item_id_to_close)
- // }
-
- // pub fn close_inactive_items(
- // &mut self,
- // _: &CloseInactiveItems,
- // cx: &mut ViewContext<Self>,
- // ) -> Option<Task<Result<()>>> {
- // if self.items.is_empty() {
- // return None;
- // }
+ pub fn close_item_by_id(
+ &mut self,
+ item_id_to_close: usize,
+ save_intent: SaveIntent,
+ cx: &mut ViewContext<Self>,
+ ) -> Task<Result<()>> {
+ self.close_items(cx, save_intent, move |view_id| view_id == item_id_to_close)
+ }
- // let active_item_id = self.items[self.active_item_index].id();
- // Some(self.close_items(cx, SaveIntent::Close, move |item_id| {
- // item_id != active_item_id
- // }))
+ // pub fn close_inactive_items(
+ // &mut self,
+ // _: &CloseInactiveItems,
+ // cx: &mut ViewContext<Self>,
+ // ) -> Option<Task<Result<()>>> {
+ // if self.items.is_empty() {
+ // return None;
// }
- // pub fn close_clean_items(
- // &mut self,
- // _: &CloseCleanItems,
- // cx: &mut ViewContext<Self>,
- // ) -> Option<Task<Result<()>>> {
- // let item_ids: Vec<_> = self
- // .items()
- // .filter(|item| !item.is_dirty(cx))
- // .map(|item| item.id())
- // .collect();
- // Some(self.close_items(cx, SaveIntent::Close, move |item_id| {
- // item_ids.contains(&item_id)
- // }))
+ // let active_item_id = self.items[self.active_item_index].id();
+ // Some(self.close_items(cx, SaveIntent::Close, move |item_id| {
+ // item_id != active_item_id
+ // }))
+ // }
+
+ // pub fn close_clean_items(
+ // &mut self,
+ // _: &CloseCleanItems,
+ // cx: &mut ViewContext<Self>,
+ // ) -> Option<Task<Result<()>>> {
+ // let item_ids: Vec<_> = self
+ // .items()
+ // .filter(|item| !item.is_dirty(cx))
+ // .map(|item| item.id())
+ // .collect();
+ // Some(self.close_items(cx, SaveIntent::Close, move |item_id| {
+ // item_ids.contains(&item_id)
+ // }))
+ // }
+
+ // pub fn close_items_to_the_left(
+ // &mut self,
+ // _: &CloseItemsToTheLeft,
+ // cx: &mut ViewContext<Self>,
+ // ) -> Option<Task<Result<()>>> {
+ // if self.items.is_empty() {
+ // return None;
// }
-
- // pub fn close_items_to_the_left(
- // &mut self,
- // _: &CloseItemsToTheLeft,
- // cx: &mut ViewContext<Self>,
- // ) -> Option<Task<Result<()>>> {
- // if self.items.is_empty() {
- // return None;
- // }
- // let active_item_id = self.items[self.active_item_index].id();
- // Some(self.close_items_to_the_left_by_id(active_item_id, cx))
+ // let active_item_id = self.items[self.active_item_index].id();
+ // Some(self.close_items_to_the_left_by_id(active_item_id, cx))
+ // }
+
+ // pub fn close_items_to_the_left_by_id(
+ // &mut self,
+ // item_id: usize,
+ // cx: &mut ViewContext<Self>,
+ // ) -> Task<Result<()>> {
+ // let item_ids: Vec<_> = self
+ // .items()
+ // .take_while(|item| item.id() != item_id)
+ // .map(|item| item.id())
+ // .collect();
+ // self.close_items(cx, SaveIntent::Close, move |item_id| {
+ // item_ids.contains(&item_id)
+ // })
+ // }
+
+ // pub fn close_items_to_the_right(
+ // &mut self,
+ // _: &CloseItemsToTheRight,
+ // cx: &mut ViewContext<Self>,
+ // ) -> Option<Task<Result<()>>> {
+ // if self.items.is_empty() {
+ // return None;
// }
-
- // pub fn close_items_to_the_left_by_id(
- // &mut self,
- // item_id: usize,
- // cx: &mut ViewContext<Self>,
- // ) -> Task<Result<()>> {
- // let item_ids: Vec<_> = self
- // .items()
- // .take_while(|item| item.id() != item_id)
- // .map(|item| item.id())
- // .collect();
- // self.close_items(cx, SaveIntent::Close, move |item_id| {
- // item_ids.contains(&item_id)
- // })
+ // let active_item_id = self.items[self.active_item_index].id();
+ // Some(self.close_items_to_the_right_by_id(active_item_id, cx))
+ // }
+
+ // pub fn close_items_to_the_right_by_id(
+ // &mut self,
+ // item_id: usize,
+ // cx: &mut ViewContext<Self>,
+ // ) -> Task<Result<()>> {
+ // let item_ids: Vec<_> = self
+ // .items()
+ // .rev()
+ // .take_while(|item| item.id() != item_id)
+ // .map(|item| item.id())
+ // .collect();
+ // self.close_items(cx, SaveIntent::Close, move |item_id| {
+ // item_ids.contains(&item_id)
+ // })
+ // }
+
+ // pub fn close_all_items(
+ // &mut self,
+ // action: &CloseAllItems,
+ // cx: &mut ViewContext<Self>,
+ // ) -> Option<Task<Result<()>>> {
+ // if self.items.is_empty() {
+ // return None;
// }
- // pub fn close_items_to_the_right(
- // &mut self,
- // _: &CloseItemsToTheRight,
- // cx: &mut ViewContext<Self>,
- // ) -> Option<Task<Result<()>>> {
- // if self.items.is_empty() {
- // return None;
- // }
- // let active_item_id = self.items[self.active_item_index].id();
- // Some(self.close_items_to_the_right_by_id(active_item_id, cx))
- // }
-
- // pub fn close_items_to_the_right_by_id(
- // &mut self,
- // item_id: usize,
- // cx: &mut ViewContext<Self>,
- // ) -> Task<Result<()>> {
- // let item_ids: Vec<_> = self
- // .items()
- // .rev()
- // .take_while(|item| item.id() != item_id)
- // .map(|item| item.id())
- // .collect();
- // self.close_items(cx, SaveIntent::Close, move |item_id| {
- // item_ids.contains(&item_id)
- // })
- // }
-
- // pub fn close_all_items(
- // &mut self,
- // action: &CloseAllItems,
- // cx: &mut ViewContext<Self>,
- // ) -> Option<Task<Result<()>>> {
- // if self.items.is_empty() {
- // return None;
- // }
-
- // Some(
- // self.close_items(cx, action.save_intent.unwrap_or(SaveIntent::Close), |_| {
- // true
- // }),
- // )
- // }
+ // Some(
+ // self.close_items(cx, action.save_intent.unwrap_or(SaveIntent::Close), |_| {
+ // true
+ // }),
+ // )
+ // }
// pub(super) fn file_names_for_prompt(
// items: &mut dyn Iterator<Item = &Box<dyn ItemHandle>>,
@@ -1156,28 +1163,29 @@ impl Pane {
// Ok(true)
// }
- // fn can_autosave_item(item: &dyn ItemHandle, cx: &AppContext) -> bool {
- // let is_deleted = item.project_entry_ids(cx).is_empty();
- // item.is_dirty(cx) && !item.has_conflict(cx) && item.can_save(cx) && !is_deleted
- // }
+ fn can_autosave_item(item: &dyn ItemHandle, cx: &AppContext) -> bool {
+ let is_deleted = item.project_entry_ids(cx).is_empty();
+ item.is_dirty(cx) && !item.has_conflict(cx) && item.can_save(cx) && !is_deleted
+ }
- // pub fn autosave_item(
- // item: &dyn ItemHandle,
- // project: Model<Project>,
- // cx: &mut WindowContext,
- // ) -> Task<Result<()>> {
- // if Self::can_autosave_item(item, cx) {
- // item.save(project, cx)
- // } else {
- // Task::ready(Ok(()))
- // }
- // }
+ pub fn autosave_item(
+ item: &dyn ItemHandle,
+ project: Model<Project>,
+ cx: &mut WindowContext,
+ ) -> Task<Result<()>> {
+ if Self::can_autosave_item(item, cx) {
+ item.save(project, cx)
+ } else {
+ Task::ready(Ok(()))
+ }
+ }
- // pub fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) {
- // if let Some(active_item) = self.active_item() {
- // cx.focus(active_item.as_any());
- // }
- // }
+ pub fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) {
+ todo!();
+ // if let Some(active_item) = self.active_item() {
+ // cx.focus(active_item.as_any());
+ // }
+ }
// pub fn split(&mut self, direction: SplitDirection, cx: &mut ViewContext<Self>) {
// cx.emit(Event::Split(direction));
@@ -1979,7 +1987,7 @@ impl NavHistory {
cx: &AppContext,
mut f: impl FnMut(&NavigationEntry, (ProjectPath, Option<PathBuf>)),
) {
- let borrowed_history = self.0.borrow();
+ let borrowed_history = self.0.lock();
borrowed_history
.forward_stack
.iter()
@@ -1990,7 +1998,7 @@ impl NavHistory {
borrowed_history.paths_by_item.get(&entry.item.id())
{
f(entry, project_and_abs_path.clone());
- } else if let Some(item) = entry.item.upgrade(cx) {
+ } else if let Some(item) = entry.item.upgrade() {
if let Some(path) = item.project_path(cx) {
f(entry, (path, None));
}
@@ -1999,23 +2007,23 @@ impl NavHistory {
}
pub fn set_mode(&mut self, mode: NavigationMode) {
- self.0.borrow_mut().mode = mode;
+ self.0.lock().mode = mode;
}
pub fn mode(&self) -> NavigationMode {
- self.0.borrow().mode
+ self.0.lock().mode
}
pub fn disable(&mut self) {
- self.0.borrow_mut().mode = NavigationMode::Disabled;
+ self.0.lock().mode = NavigationMode::Disabled;
}
pub fn enable(&mut self) {
- self.0.borrow_mut().mode = NavigationMode::Normal;
+ self.0.lock().mode = NavigationMode::Normal;
}
pub fn pop(&mut self, mode: NavigationMode, cx: &mut WindowContext) -> Option<NavigationEntry> {
- let mut state = self.0.borrow_mut();
+ let mut state = self.0.lock();
let entry = match mode {
NavigationMode::Normal | NavigationMode::Disabled | NavigationMode::ClosingItem => {
return None
@@ -2034,10 +2042,10 @@ impl NavHistory {
pub fn push<D: 'static + Any>(
&mut self,
data: Option<D>,
- item: Rc<dyn WeakItemHandle>,
+ item: Arc<dyn WeakItemHandle>,
cx: &mut WindowContext,
) {
- let state = &mut *self.0.borrow_mut();
+ let state = &mut *self.0.lock();
match state.mode {
NavigationMode::Disabled => {}
NavigationMode::Normal | NavigationMode::ReopeningClosedItem => {
@@ -2086,7 +2094,7 @@ impl NavHistory {
}
pub fn remove_item(&mut self, item_id: usize) {
- let mut state = self.0.borrow_mut();
+ let mut state = self.0.lock();
state.paths_by_item.remove(&item_id);
state
.backward_stack
@@ -2100,19 +2108,19 @@ impl NavHistory {
}
pub fn path_for_item(&self, item_id: usize) -> Option<(ProjectPath, Option<PathBuf>)> {
- self.0.borrow().paths_by_item.get(&item_id).cloned()
+ self.0.lock().paths_by_item.get(&item_id).cloned()
}
}
-// impl NavHistoryState {
-// pub fn did_update(&self, cx: &mut WindowContext) {
-// if let Some(pane) = self.pane.upgrade(cx) {
-// cx.defer(move |cx| {
-// pane.update(cx, |pane, cx| pane.history_updated(cx));
-// });
-// }
-// }
-// }
+impl NavHistoryState {
+ pub fn did_update(&self, cx: &mut WindowContext) {
+ if let Some(pane) = self.pane.upgrade() {
+ cx.defer(move |cx| {
+ pane.update(cx, |pane, cx| pane.history_updated(cx));
+ });
+ }
+ }
+}
// pub struct PaneBackdrop<V> {
// child_view: usize,
@@ -1,7 +1,7 @@
use crate::ItemHandle;
-use gpui2::{AppContext, EventEmitter, View, ViewContext, WindowContext};
+use gpui2::{AnyView, AppContext, EventEmitter, Render, View, ViewContext, WindowContext};
-pub trait ToolbarItemView: EventEmitter + Sized {
+pub trait ToolbarItemView: Render + EventEmitter {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn crate::ItemHandle>,
@@ -22,14 +22,14 @@ pub trait ToolbarItemView: EventEmitter + Sized {
/// Number of times toolbar's height will be repeated to get the effective height.
/// Useful when multiple rows one under each other are needed.
/// The rows have the same width and act as a whole when reacting to resizes and similar events.
- fn row_count(&self, _cx: &ViewContext<Self>) -> usize {
+ fn row_count(&self, _cx: &WindowContext) -> usize {
1
}
}
-trait ToolbarItemViewHandle {
+trait ToolbarItemViewHandle: Send {
fn id(&self) -> usize;
- // fn as_any(&self) -> &AnyViewHandle; todo!()
+ fn to_any(&self) -> AnyView;
fn set_active_pane_item(
&self,
active_pane_item: Option<&dyn ItemHandle>,
@@ -249,7 +249,7 @@ impl Toolbar {
pub fn item_of_type<T: ToolbarItemView>(&self) -> Option<View<T>> {
self.items
.iter()
- .find_map(|(item, _)| item.as_any().clone().downcast())
+ .find_map(|(item, _)| item.to_any().downcast().ok())
}
pub fn hidden(&self) -> bool {
@@ -262,10 +262,9 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
self.id()
}
- // todo!()
- // fn as_any(&self) -> &AnyViewHandle {
- // self
- // }
+ fn to_any(&self) -> AnyView {
+ self.clone().into_any()
+ }
fn set_active_pane_item(
&self,
@@ -285,7 +284,7 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
}
fn row_count(&self, cx: &WindowContext) -> usize {
- self.read_with(cx, |this, cx| this.row_count(cx))
+ self.read(cx).row_count(cx)
}
}
@@ -36,6 +36,10 @@ use std::{
pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
use util::ResultExt;
+use crate::persistence::model::{
+ DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup,
+};
+
// lazy_static! {
// static ref ZED_WINDOW_SIZE: Option<Vector2F> = env::var("ZED_WINDOW_SIZE")
// .ok()
@@ -514,9 +518,9 @@ pub struct Workspace {
// zoomed: Option<AnyWeakViewHandle>,
// zoomed_position: Option<DockPosition>,
// center: PaneGroup,
- // left_dock: View<Dock>,
- // bottom_dock: View<Dock>,
- // right_dock: View<Dock>,
+ left_dock: View<Dock>,
+ bottom_dock: View<Dock>,
+ right_dock: View<Dock>,
panes: Vec<View<Pane>>,
panes_by_item: HashMap<usize, WeakView<Pane>>,
// active_pane: View<Pane>,
@@ -526,8 +530,8 @@ pub struct Workspace {
// titlebar_item: Option<AnyViewHandle>,
// notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
project: Model<Project>,
- // follower_states: HashMap<View<Pane>, FollowerState>,
- // last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>,
+ follower_states: HashMap<View<Pane>, FollowerState>,
+ last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>,
// window_edited: bool,
// active_call: Option<(ModelHandle<ActiveCall>, Vec<Subscription>)>,
// leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
@@ -2613,37 +2617,33 @@ impl Workspace {
// self.start_following(leader_id, cx)
// }
- // pub fn unfollow(
- // &mut self,
- // pane: &View<Pane>,
- // cx: &mut ViewContext<Self>,
- // ) -> Option<PeerId> {
- // let state = self.follower_states.remove(pane)?;
- // let leader_id = state.leader_id;
- // for (_, item) in state.items_by_leader_view_id {
- // item.set_leader_peer_id(None, cx);
- // }
+ pub fn unfollow(&mut self, pane: &View<Pane>, cx: &mut ViewContext<Self>) -> Option<PeerId> {
+ let state = self.follower_states.remove(pane)?;
+ let leader_id = state.leader_id;
+ for (_, item) in state.items_by_leader_view_id {
+ item.set_leader_peer_id(None, cx);
+ }
- // if self
- // .follower_states
- // .values()
- // .all(|state| state.leader_id != state.leader_id)
- // {
- // let project_id = self.project.read(cx).remote_id();
- // let room_id = self.active_call()?.read(cx).room()?.read(cx).id();
- // self.app_state
- // .client
- // .send(proto::Unfollow {
- // room_id,
- // project_id,
- // leader_id: Some(leader_id),
- // })
- // .log_err();
- // }
+ if self
+ .follower_states
+ .values()
+ .all(|state| state.leader_id != state.leader_id)
+ {
+ let project_id = self.project.read(cx).remote_id();
+ let room_id = self.active_call()?.read(cx).room()?.read(cx).id();
+ self.app_state
+ .client
+ .send(proto::Unfollow {
+ room_id,
+ project_id,
+ leader_id: Some(leader_id),
+ })
+ .log_err();
+ }
- // cx.notify();
- // Some(leader_id)
- // }
+ cx.notify();
+ Some(leader_id)
+ }
// pub fn is_being_followed(&self, peer_id: PeerId) -> bool {
// self.follower_states
@@ -3210,137 +3210,134 @@ impl Workspace {
// }));
// }
- // fn serialize_workspace(&self, cx: &ViewContext<Self>) {
- // fn serialize_pane_handle(
- // pane_handle: &View<Pane>,
- // cx: &AppContext,
- // ) -> SerializedPane {
- // let (items, active) = {
- // let pane = pane_handle.read(cx);
- // let active_item_id = pane.active_item().map(|item| item.id());
- // (
- // pane.items()
- // .filter_map(|item_handle| {
- // Some(SerializedItem {
- // kind: Arc::from(item_handle.serialized_item_kind()?),
- // item_id: item_handle.id(),
- // active: Some(item_handle.id()) == active_item_id,
- // })
- // })
- // .collect::<Vec<_>>(),
- // pane.has_focus(),
- // )
- // };
+ fn serialize_workspace(&self, cx: &ViewContext<Self>) {
+ fn serialize_pane_handle(pane_handle: &View<Pane>, cx: &AppContext) -> SerializedPane {
+ let (items, active) = {
+ let pane = pane_handle.read(cx);
+ let active_item_id = pane.active_item().map(|item| item.id());
+ (
+ pane.items()
+ .filter_map(|item_handle| {
+ Some(SerializedItem {
+ kind: Arc::from(item_handle.serialized_item_kind()?),
+ item_id: item_handle.id(),
+ active: Some(item_handle.id()) == active_item_id,
+ })
+ })
+ .collect::<Vec<_>>(),
+ pane.has_focus(),
+ )
+ };
- // SerializedPane::new(items, active)
- // }
+ SerializedPane::new(items, active)
+ }
- // fn build_serialized_pane_group(
- // pane_group: &Member,
- // cx: &AppContext,
- // ) -> SerializedPaneGroup {
- // match pane_group {
- // Member::Axis(PaneAxis {
- // axis,
- // members,
- // flexes,
- // bounding_boxes: _,
- // }) => SerializedPaneGroup::Group {
- // axis: *axis,
- // children: members
- // .iter()
- // .map(|member| build_serialized_pane_group(member, cx))
- // .collect::<Vec<_>>(),
- // flexes: Some(flexes.borrow().clone()),
- // },
- // Member::Pane(pane_handle) => {
- // SerializedPaneGroup::Pane(serialize_pane_handle(&pane_handle, cx))
- // }
- // }
- // }
+ fn build_serialized_pane_group(
+ pane_group: &Member,
+ cx: &AppContext,
+ ) -> SerializedPaneGroup {
+ match pane_group {
+ Member::Axis(PaneAxis {
+ axis,
+ members,
+ flexes,
+ bounding_boxes: _,
+ }) => SerializedPaneGroup::Group {
+ axis: *axis,
+ children: members
+ .iter()
+ .map(|member| build_serialized_pane_group(member, cx))
+ .collect::<Vec<_>>(),
+ flexes: Some(flexes.borrow().clone()),
+ },
+ Member::Pane(pane_handle) => {
+ SerializedPaneGroup::Pane(serialize_pane_handle(&pane_handle, cx))
+ }
+ }
+ }
- // fn build_serialized_docks(this: &Workspace, cx: &ViewContext<Workspace>) -> DockStructure {
- // let left_dock = this.left_dock.read(cx);
- // let left_visible = left_dock.is_open();
- // let left_active_panel = left_dock.visible_panel().and_then(|panel| {
- // Some(
- // cx.view_ui_name(panel.as_any().window(), panel.id())?
- // .to_string(),
- // )
- // });
- // let left_dock_zoom = left_dock
- // .visible_panel()
- // .map(|panel| panel.is_zoomed(cx))
- // .unwrap_or(false);
-
- // let right_dock = this.right_dock.read(cx);
- // let right_visible = right_dock.is_open();
- // let right_active_panel = right_dock.visible_panel().and_then(|panel| {
- // Some(
- // cx.view_ui_name(panel.as_any().window(), panel.id())?
- // .to_string(),
- // )
- // });
- // let right_dock_zoom = right_dock
- // .visible_panel()
- // .map(|panel| panel.is_zoomed(cx))
- // .unwrap_or(false);
-
- // let bottom_dock = this.bottom_dock.read(cx);
- // let bottom_visible = bottom_dock.is_open();
- // let bottom_active_panel = bottom_dock.visible_panel().and_then(|panel| {
- // Some(
- // cx.view_ui_name(panel.as_any().window(), panel.id())?
- // .to_string(),
- // )
- // });
- // let bottom_dock_zoom = bottom_dock
- // .visible_panel()
- // .map(|panel| panel.is_zoomed(cx))
- // .unwrap_or(false);
-
- // DockStructure {
- // left: DockData {
- // visible: left_visible,
- // active_panel: left_active_panel,
- // zoom: left_dock_zoom,
- // },
- // right: DockData {
- // visible: right_visible,
- // active_panel: right_active_panel,
- // zoom: right_dock_zoom,
- // },
- // bottom: DockData {
- // visible: bottom_visible,
- // active_panel: bottom_active_panel,
- // zoom: bottom_dock_zoom,
- // },
- // }
- // }
+ fn build_serialized_docks(this: &Workspace, cx: &ViewContext<Workspace>) -> DockStructure {
+ let left_dock = this.left_dock.read(cx);
+ let left_visible = left_dock.is_open();
+ let left_active_panel = left_dock.visible_panel().and_then(|panel| {
+ Some(
+ cx.view_ui_name(panel.as_any().window(), panel.id())?
+ .to_string(),
+ )
+ });
+ let left_dock_zoom = left_dock
+ .visible_panel()
+ .map(|panel| panel.is_zoomed(cx))
+ .unwrap_or(false);
- // if let Some(location) = self.location(cx) {
- // // Load bearing special case:
- // // - with_local_workspace() relies on this to not have other stuff open
- // // when you open your log
- // if !location.paths().is_empty() {
- // let center_group = build_serialized_pane_group(&self.center.root, cx);
- // let docks = build_serialized_docks(self, cx);
-
- // let serialized_workspace = SerializedWorkspace {
- // id: self.database_id,
- // location,
- // center_group,
- // bounds: Default::default(),
- // display: Default::default(),
- // docks,
- // };
+ let right_dock = this.right_dock.read(cx);
+ let right_visible = right_dock.is_open();
+ let right_active_panel = right_dock.visible_panel().and_then(|panel| {
+ Some(
+ cx.view_ui_name(panel.as_any().window(), panel.id())?
+ .to_string(),
+ )
+ });
+ let right_dock_zoom = right_dock
+ .visible_panel()
+ .map(|panel| panel.is_zoomed(cx))
+ .unwrap_or(false);
- // cx.background()
- // .spawn(persistence::DB.save_workspace(serialized_workspace))
- // .detach();
- // }
- // }
- // }
+ let bottom_dock = this.bottom_dock.read(cx);
+ let bottom_visible = bottom_dock.is_open();
+ let bottom_active_panel = bottom_dock.visible_panel().and_then(|panel| {
+ Some(
+ cx.view_ui_name(panel.as_any().window(), panel.id())?
+ .to_string(),
+ )
+ });
+ let bottom_dock_zoom = bottom_dock
+ .visible_panel()
+ .map(|panel| panel.is_zoomed(cx))
+ .unwrap_or(false);
+
+ DockStructure {
+ left: DockData {
+ visible: left_visible,
+ active_panel: left_active_panel,
+ zoom: left_dock_zoom,
+ },
+ right: DockData {
+ visible: right_visible,
+ active_panel: right_active_panel,
+ zoom: right_dock_zoom,
+ },
+ bottom: DockData {
+ visible: bottom_visible,
+ active_panel: bottom_active_panel,
+ zoom: bottom_dock_zoom,
+ },
+ }
+ }
+
+ if let Some(location) = self.location(cx) {
+ // Load bearing special case:
+ // - with_local_workspace() relies on this to not have other stuff open
+ // when you open your log
+ if !location.paths().is_empty() {
+ let center_group = build_serialized_pane_group(&self.center.root, cx);
+ let docks = build_serialized_docks(self, cx);
+
+ let serialized_workspace = SerializedWorkspace {
+ id: self.database_id,
+ location,
+ center_group,
+ bounds: Default::default(),
+ display: Default::default(),
+ docks,
+ };
+
+ cx.background()
+ .spawn(persistence::DB.save_workspace(serialized_workspace))
+ .detach();
+ }
+ }
+ }
// pub(crate) fn load_workspace(
// workspace: WeakView<Workspace>,