@@ -107,12 +107,6 @@ pub struct Pane {
active_toolbar_visible: bool,
}
-pub(crate) struct FollowerState {
- pub(crate) leader_id: PeerId,
- pub(crate) current_view_id: Option<usize>,
- pub(crate) items_by_leader_view_id: HashMap<usize, Box<dyn ItemHandle>>,
-}
-
pub trait Toolbar: View {
fn active_item_changed(
&mut self,
@@ -266,7 +260,17 @@ impl Pane {
if let Some((project_entry_id, build_item)) = task.log_err() {
pane.update(&mut cx, |pane, cx| {
pane.nav_history.borrow_mut().set_mode(mode);
- let item = pane.open_item(project_entry_id, cx, build_item);
+ });
+ let item = workspace.update(&mut cx, |workspace, cx| {
+ Self::open_item(
+ workspace,
+ pane.clone(),
+ project_entry_id,
+ cx,
+ build_item,
+ )
+ });
+ pane.update(&mut cx, |pane, cx| {
pane.nav_history
.borrow_mut()
.set_mode(NavigationMode::Normal);
@@ -289,52 +293,50 @@ impl Pane {
}
pub(crate) fn open_item(
- &mut self,
+ workspace: &mut Workspace,
+ pane: ViewHandle<Pane>,
project_entry_id: ProjectEntryId,
- cx: &mut ViewContext<Self>,
+ cx: &mut ViewContext<Workspace>,
build_item: impl FnOnce(&mut MutableAppContext) -> Box<dyn ItemHandle>,
) -> Box<dyn ItemHandle> {
- for (ix, item) in self.items.iter().enumerate() {
- if item.project_entry_id(cx) == Some(project_entry_id) {
- let item = item.boxed_clone();
- self.activate_item(ix, cx);
- return item;
+ let existing_item = pane.update(cx, |pane, cx| {
+ for (ix, item) in pane.items.iter().enumerate() {
+ if item.project_entry_id(cx) == Some(project_entry_id) {
+ let item = item.boxed_clone();
+ pane.activate_item(ix, cx);
+ return Some(item);
+ }
}
+ None
+ });
+ if let Some(existing_item) = existing_item {
+ existing_item
+ } else {
+ let item = build_item(cx);
+ Self::add_item(workspace, pane, item.boxed_clone(), cx);
+ item
}
-
- let item = build_item(cx);
- self.add_item(item.boxed_clone(), cx);
- item
}
- pub(crate) fn add_item(&mut self, mut item: Box<dyn ItemHandle>, cx: &mut ViewContext<Self>) {
+ pub(crate) fn add_item(
+ workspace: &mut Workspace,
+ pane: ViewHandle<Pane>,
+ mut item: Box<dyn ItemHandle>,
+ cx: &mut ViewContext<Workspace>,
+ ) {
// Prevent adding the same item to the pane more than once.
- if self.items.iter().any(|i| i.id() == item.id()) {
+ if pane.read(cx).items.iter().any(|i| i.id() == item.id()) {
return;
}
- item.set_nav_history(self.nav_history.clone(), cx);
- item.added_to_pane(cx);
- let item_idx = cmp::min(self.active_item_index + 1, self.items.len());
- self.items.insert(item_idx, item);
- self.activate_item(item_idx, cx);
- cx.notify();
- }
-
- pub(crate) fn set_follow_state(
- &mut self,
- follower_state: FollowerState,
- cx: &mut ViewContext<Self>,
- ) -> Result<()> {
- if let Some(current_view_id) = follower_state.current_view_id {
- let item = follower_state
- .items_by_leader_view_id
- .get(¤t_view_id)
- .ok_or_else(|| anyhow!("invalid current view id"))?
- .clone();
- self.add_item(item, cx);
- }
- Ok(())
+ item.set_nav_history(pane.read(cx).nav_history.clone(), cx);
+ item.added_to_pane(workspace, pane.clone(), cx);
+ pane.update(cx, |pane, cx| {
+ let item_idx = cmp::min(pane.active_item_index + 1, pane.items.len());
+ pane.items.insert(item_idx, item);
+ pane.activate_item(item_idx, cx);
+ cx.notify();
+ });
}
pub fn items(&self) -> impl Iterator<Item = &Box<dyn ItemHandle>> {
@@ -284,7 +284,12 @@ pub trait ItemHandle: 'static {
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
fn set_nav_history(&self, nav_history: Rc<RefCell<NavHistory>>, cx: &mut MutableAppContext);
fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option<Box<dyn ItemHandle>>;
- fn added_to_pane(&mut self, cx: &mut ViewContext<Pane>);
+ fn added_to_pane(
+ &self,
+ workspace: &mut Workspace,
+ pane: ViewHandle<Pane>,
+ cx: &mut ViewContext<Workspace>,
+ );
fn deactivated(&self, cx: &mut MutableAppContext);
fn navigate(&self, data: Box<dyn Any>, cx: &mut MutableAppContext);
fn id(&self) -> usize;
@@ -350,22 +355,37 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
})
}
- fn added_to_pane(&mut self, cx: &mut ViewContext<Pane>) {
- cx.subscribe(self, |pane, item, event, cx| {
+ fn added_to_pane(
+ &self,
+ workspace: &mut Workspace,
+ pane: ViewHandle<Pane>,
+ cx: &mut ViewContext<Workspace>,
+ ) {
+ let pane = pane.downgrade();
+ cx.subscribe(self, move |workspace, item, event, cx| {
+ let pane = if let Some(pane) = pane.upgrade(cx) {
+ pane
+ } else {
+ log::error!("unexpected item event after pane was dropped");
+ return;
+ };
+
if T::should_close_item_on_event(event) {
- pane.close_item(item.id(), cx);
+ pane.update(cx, |pane, cx| pane.close_item(item.id(), cx));
return;
}
if T::should_activate_item_on_event(event) {
- if let Some(ix) = pane.index_for_item(&item) {
- pane.activate_item(ix, cx);
- pane.activate(cx);
- }
+ pane.update(cx, |pane, cx| {
+ if let Some(ix) = pane.index_for_item(&item) {
+ pane.activate_item(ix, cx);
+ pane.activate(cx);
+ }
+ });
}
if T::should_update_tab_on_event(event) {
- cx.notify()
+ pane.update(cx, |_, cx| cx.notify());
}
if let Some(message) = item
@@ -533,6 +553,7 @@ pub struct Workspace {
status_bar: ViewHandle<StatusBar>,
project: ModelHandle<Project>,
leader_state: LeaderState,
+ follower_states_by_leader: HashMap<PeerId, FollowerState>,
_observe_current_user: Task<()>,
}
@@ -542,6 +563,11 @@ struct LeaderState {
subscriptions: Vec<Subscription>,
}
+struct FollowerState {
+ current_view_id: Option<usize>,
+ items_by_leader_view_id: HashMap<usize, Box<dyn ItemHandle>>,
+}
+
impl Workspace {
pub fn new(params: &WorkspaceParams, cx: &mut ViewContext<Self>) -> Self {
cx.observe(¶ms.project, |_, project, cx| {
@@ -614,6 +640,7 @@ impl Workspace {
right_sidebar: Sidebar::new(Side::Right),
project: params.project.clone(),
leader_state: Default::default(),
+ follower_states_by_leader: Default::default(),
_observe_current_user,
};
this.project_remote_id_changed(this.project.read(cx).remote_id(), cx);
@@ -910,8 +937,8 @@ impl Workspace {
}
pub fn add_item(&mut self, item: Box<dyn ItemHandle>, cx: &mut ViewContext<Self>) {
- self.active_pane()
- .update(cx, |pane, cx| pane.add_item(item, cx))
+ let pane = self.active_pane().clone();
+ Pane::add_item(self, pane, item, cx);
}
pub fn open_path(
@@ -926,10 +953,14 @@ impl Workspace {
let pane = pane
.upgrade(&cx)
.ok_or_else(|| anyhow!("pane was closed"))?;
- this.update(&mut cx, |_, cx| {
- pane.update(cx, |pane, cx| {
- Ok(pane.open_item(project_entry_id, cx, build_item))
- })
+ this.update(&mut cx, |this, cx| {
+ Ok(Pane::open_item(
+ this,
+ pane,
+ project_entry_id,
+ cx,
+ build_item,
+ ))
})
})
}
@@ -1057,9 +1088,7 @@ impl Workspace {
self.activate_pane(new_pane.clone(), cx);
if let Some(item) = pane.read(cx).active_item() {
if let Some(clone) = item.clone_on_split(cx.as_mut()) {
- new_pane.update(cx, |new_pane, cx| {
- new_pane.add_item(clone, cx);
- });
+ Pane::add_item(self, new_pane.clone(), clone, cx);
}
}
self.center.split(&pane, &new_pane, direction).unwrap();
@@ -1149,21 +1178,32 @@ impl Workspace {
}
let items = futures::future::try_join_all(item_tasks).await?;
- let mut items_by_leader_view_id = HashMap::default();
- for (view, item) in response.views.into_iter().zip(items) {
- items_by_leader_view_id.insert(view.id as usize, item);
- }
-
- pane.update(&mut cx, |pane, cx| {
- pane.set_follow_state(
- FollowerState {
- leader_id,
- current_view_id: response.current_view_id.map(|id| id as usize),
- items_by_leader_view_id,
- },
- cx,
+ let follower_state = FollowerState {
+ current_view_id: response.current_view_id.map(|id| id as usize),
+ items_by_leader_view_id: response
+ .views
+ .iter()
+ .map(|v| v.id as usize)
+ .zip(items)
+ .collect(),
+ };
+ let current_item = if let Some(current_view_id) = follower_state.current_view_id
+ {
+ Some(
+ follower_state
+ .items_by_leader_view_id
+ .get(¤t_view_id)
+ .ok_or_else(|| anyhow!("invalid current view id"))?
+ .clone(),
)
- })?;
+ } else {
+ None
+ };
+ this.update(&mut cx, |this, cx| {
+ if let Some(item) = current_item {
+ Pane::add_item(this, pane, item, cx);
+ }
+ });
}
Ok(())
})