diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index 761b5737ce86b27c8d1da548ef0fff7bfedba94b..047912c0ffd951890bfba11a7e37ed88525aead8 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -4578,6 +4578,44 @@ mod tests { workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), None ); + + workspace_b + .update(cx_b, |workspace, cx| { + workspace.toggle_follow(&leader_id.into(), cx).unwrap() + }) + .await + .unwrap(); + assert_eq!( + workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), + Some(leader_id) + ); + + // When client B activates a different pane, it continues following client A in the original pane. + workspace_b.update(cx_b, |workspace, cx| { + workspace.split_pane(pane_b.clone(), SplitDirection::Right, cx) + }); + assert_eq!( + workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), + Some(leader_id) + ); + + workspace_b.update(cx_b, |workspace, cx| workspace.activate_next_pane(cx)); + assert_eq!( + workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), + Some(leader_id) + ); + + // When client B activates a different item in the original pane, it automatically stops following client A. + workspace_b + .update(cx_b, |workspace, cx| { + workspace.open_path((worktree_id, "2.txt"), cx) + }) + .await + .unwrap(); + assert_eq!( + workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)), + None + ); } #[gpui::test(iterations = 100)] diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 367cc967fca85baf5a111341c9e4a914f3139055..ab54b0053e461bdd9111d78ab941add7c40b4b3b 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -33,7 +33,7 @@ const MAX_NAVIGATION_HISTORY_LEN: usize = 1024; pub fn init(cx: &mut MutableAppContext) { cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| { - pane.activate_item(action.0, cx); + pane.activate_item(action.0, true, cx); }); cx.add_action(|pane: &mut Pane, _: &ActivatePrevItem, cx| { pane.activate_prev_item(cx); @@ -92,6 +92,7 @@ pub fn init(cx: &mut MutableAppContext) { pub enum Event { Activate, + ActivateItem { local: bool }, Remove, Split(SplitDirection), } @@ -301,7 +302,7 @@ impl Pane { 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); + pane.activate_item(ix, true, cx); return Some(item); } } @@ -311,7 +312,7 @@ impl Pane { existing_item } else { let item = build_item(cx); - Self::add_item(workspace, pane, item.boxed_clone(), cx); + Self::add_item(workspace, pane, item.boxed_clone(), true, cx); item } } @@ -320,11 +321,12 @@ impl Pane { workspace: &mut Workspace, pane: ViewHandle, item: Box, + local: bool, cx: &mut ViewContext, ) { // Prevent adding the same item to the pane more than once. if let Some(item_ix) = pane.read(cx).items.iter().position(|i| i.id() == item.id()) { - pane.update(cx, |pane, cx| pane.activate_item(item_ix, cx)); + pane.update(cx, |pane, cx| pane.activate_item(item_ix, local, cx)); return; } @@ -333,7 +335,7 @@ impl Pane { 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); + pane.activate_item(item_idx, local, cx); cx.notify(); }); } @@ -384,13 +386,14 @@ impl Pane { self.items.iter().position(|i| i.id() == item.id()) } - pub fn activate_item(&mut self, index: usize, cx: &mut ViewContext) { + pub fn activate_item(&mut self, index: usize, local: bool, cx: &mut ViewContext) { if index < self.items.len() { let prev_active_item_ix = mem::replace(&mut self.active_item_index, index); if prev_active_item_ix != self.active_item_index && prev_active_item_ix < self.items.len() { self.items[prev_active_item_ix].deactivated(cx); + cx.emit(Event::ActivateItem { local }); } self.update_active_toolbar(cx); self.focus_active_item(cx); @@ -406,7 +409,7 @@ impl Pane { } else if self.items.len() > 0 { index = self.items.len() - 1; } - self.activate_item(index, cx); + self.activate_item(index, true, cx); } pub fn activate_next_item(&mut self, cx: &mut ViewContext) { @@ -416,7 +419,7 @@ impl Pane { } else { index = 0; } - self.activate_item(index, cx); + self.activate_item(index, true, cx); } pub fn close_active_item(&mut self, cx: &mut ViewContext) { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cb9f7e7fed92b6c7b62433d05c11f93dcd05b3bf..9c8da079ae1af0817eaebe0548129d7b160be5ad 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -445,7 +445,7 @@ impl ItemHandle for ViewHandle { if T::should_activate_item_on_event(event) { pane.update(cx, |pane, cx| { if let Some(ix) = pane.index_for_item(&item) { - pane.activate_item(ix, cx); + pane.activate_item(ix, true, cx); pane.activate(cx); } }); @@ -1022,7 +1022,7 @@ impl Workspace { pub fn add_item(&mut self, item: Box, cx: &mut ViewContext) { let pane = self.active_pane().clone(); - Pane::add_item(self, pane, item, cx); + Pane::add_item(self, pane, item, true, cx); } pub fn open_path( @@ -1111,7 +1111,7 @@ impl Workspace { }); if let Some((pane, ix)) = result { self.activate_pane(pane.clone(), cx); - pane.update(cx, |pane, cx| pane.activate_item(ix, cx)); + pane.update(cx, |pane, cx| pane.activate_item(ix, true, cx)); true } else { false @@ -1164,6 +1164,11 @@ impl Workspace { pane::Event::Activate => { self.activate_pane(pane, cx); } + pane::Event::ActivateItem { local } => { + if *local { + self.unfollow(&pane, cx); + } + } } } else { error!("pane {} not found", pane_id); @@ -1180,7 +1185,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()) { - Pane::add_item(self, new_pane.clone(), clone, cx); + Pane::add_item(self, new_pane.clone(), clone, true, cx); } } self.center.split(&pane, &new_pane, direction).unwrap(); @@ -1793,7 +1798,7 @@ impl Workspace { } for (pane, item) in items_to_add { - Pane::add_item(self, pane.clone(), item.boxed_clone(), cx); + Pane::add_item(self, pane.clone(), item.boxed_clone(), false, cx); cx.notify(); } None