From e5a99cf8cd01e9e977aa2f9442e081574f515d66 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 22 Mar 2022 11:15:39 +0100 Subject: [PATCH] Stop following when leader disconnects --- crates/project/src/project.rs | 2 ++ crates/server/src/rpc.rs | 44 +++++++++++++++++++++++++------ crates/workspace/src/workspace.rs | 24 +++++++++++++++-- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 5f9a63c034d88711577aafad022584078504407a..c3c2f4e2a036e52c58b76a8a85d985f33180aa94 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -125,6 +125,7 @@ pub enum Event { DiskBasedDiagnosticsFinished, DiagnosticsUpdated(ProjectPath), RemoteIdChanged(Option), + CollaboratorLeft(PeerId), } enum LanguageServerEvent { @@ -3368,6 +3369,7 @@ impl Project { buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx)); } } + cx.emit(Event::CollaboratorLeft(peer_id)); cx.notify(); Ok(()) }) diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index 3f149390d35e91b751cda9eeab5c706e2ed11109..3274e70d61fa612e93366611df196e57a91d5939 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -4259,6 +4259,7 @@ mod tests { // Client A opens some editors. let workspace_a = client_a.build_workspace(&project_a, cx_a); + let pane_a = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone()); let editor_a1 = workspace_a .update(cx_a, |workspace, cx| { workspace.open_path((worktree_id, "1.txt"), cx) @@ -4287,19 +4288,19 @@ mod tests { .downcast::() .unwrap(); + let client_a_id = project_b.read_with(cx_b, |project, _| { + project.collaborators().values().next().unwrap().peer_id + }); + let client_b_id = project_a.read_with(cx_a, |project, _| { + project.collaborators().values().next().unwrap().peer_id + }); + // When client B starts following client A, all visible view states are replicated to client B. editor_a1.update(cx_a, |editor, cx| editor.select_ranges([0..1], None, cx)); editor_a2.update(cx_a, |editor, cx| editor.select_ranges([2..3], None, cx)); workspace_b .update(cx_b, |workspace, cx| { - let leader_id = project_b - .read(cx) - .collaborators() - .values() - .next() - .unwrap() - .peer_id; - workspace.toggle_follow(&leader_id.into(), cx).unwrap() + workspace.toggle_follow(&client_a_id.into(), cx).unwrap() }) .await .unwrap(); @@ -4370,6 +4371,33 @@ mod tests { .id()), editor_b1.id() ); + + // Client A starts following client B. + workspace_a + .update(cx_a, |workspace, cx| { + workspace.toggle_follow(&client_b_id.into(), cx).unwrap() + }) + .await + .unwrap(); + assert_eq!( + workspace_a.read_with(cx_a, |workspace, _| workspace.leader_for_pane(&pane_a)), + Some(client_b_id) + ); + assert_eq!( + workspace_a.read_with(cx_a, |workspace, cx| workspace + .active_item(cx) + .unwrap() + .id()), + editor_a1.id() + ); + + // Following interrupts when client B disconnects. + client_b.disconnect(&cx_b.to_async()).unwrap(); + cx_a.foreground().run_until_parked(); + assert_eq!( + workspace_a.read_with(cx_a, |workspace, _| workspace.leader_for_pane(&pane_a)), + None + ); } #[gpui::test(iterations = 10)] diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 1f0a89a083a924d8b25791dd55da849c8e52dfaa..353c3f251088bdb0697ec991bbf39f05d607564b 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -667,8 +667,14 @@ impl Workspace { .detach(); cx.subscribe(¶ms.project, move |this, project, event, cx| { - if let project::Event::RemoteIdChanged(remote_id) = event { - this.project_remote_id_changed(*remote_id, cx); + match event { + project::Event::RemoteIdChanged(remote_id) => { + this.project_remote_id_changed(*remote_id, cx); + } + project::Event::CollaboratorLeft(peer_id) => { + this.collaborator_left(*peer_id, cx); + } + _ => {} } if project.read(cx).is_read_only() { cx.blur(); @@ -1241,6 +1247,20 @@ impl Workspace { } } + fn collaborator_left(&mut self, peer_id: PeerId, cx: &mut ViewContext) { + self.leader_state.followers.remove(&peer_id); + if let Some(states_by_pane) = self.follower_states_by_leader.remove(&peer_id) { + for state in states_by_pane.into_values() { + for item in state.items_by_leader_view_id.into_values() { + if let FollowerItem::Loaded(item) = item { + item.set_leader_replica_id(None, cx); + } + } + } + } + cx.notify(); + } + pub fn toggle_follow( &mut self, ToggleFollow(leader_id): &ToggleFollow,