From cfbd8b94d12a9dac2fb1f725234315850a1c1e2b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 14 Jun 2022 14:47:16 +0200 Subject: [PATCH 1/3] Prevent setting files from showing up in project and contacts panels --- crates/journal/src/journal.rs | 2 +- crates/workspace/src/workspace.rs | 41 ++++++++++++++------ crates/zed/src/zed.rs | 63 ++++++++++++++++++++++++++++--- 3 files changed, 87 insertions(+), 19 deletions(-) diff --git a/crates/journal/src/journal.rs b/crates/journal/src/journal.rs index 13ef3a2420dbfcab34dfd2e17383576cf33d86d7..8135950e50cb9bd9ae1e7cff567b8dc411e2106e 100644 --- a/crates/journal/src/journal.rs +++ b/crates/journal/src/journal.rs @@ -49,7 +49,7 @@ pub fn new_journal_entry(app_state: Arc, cx: &mut MutableAppContext) { let opened = workspace .update(&mut cx, |workspace, cx| { - workspace.open_paths(vec![entry_path], cx) + workspace.open_paths(vec![entry_path], true, cx) }) .await; diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 851c3403d212ff9ed06de46c8f7ad110015d004e..aed1bf5b46aecdb4d619744b37b2d973d60be03a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -885,6 +885,13 @@ impl Workspace { self.project.read(cx).worktrees(cx) } + pub fn visible_worktrees<'a>( + &self, + cx: &'a AppContext, + ) -> impl 'a + Iterator> { + self.project.read(cx).visible_worktrees(cx) + } + pub fn worktree_scans_complete(&self, cx: &AppContext) -> impl Future + 'static { let futures = self .worktrees(cx) @@ -974,6 +981,7 @@ impl Workspace { pub fn open_paths( &mut self, mut abs_paths: Vec, + visible: bool, cx: &mut ViewContext, ) -> Task, Arc>>>> { let fs = self.fs.clone(); @@ -984,9 +992,11 @@ impl Workspace { let mut entries = Vec::new(); for path in &abs_paths { entries.push( - this.update(&mut cx, |this, cx| this.project_path_for_path(path, cx)) - .await - .ok(), + this.update(&mut cx, |this, cx| { + this.project_path_for_path(path, visible, cx) + }) + .await + .log_err(), ); } @@ -999,7 +1009,7 @@ impl Workspace { cx.spawn(|mut cx| { let fs = fs.clone(); async move { - let project_path = project_path?; + let (_worktree, project_path) = project_path?; if fs.is_file(&abs_path).await { Some( this.update(&mut cx, |this, cx| { @@ -1028,7 +1038,7 @@ impl Workspace { cx.spawn(|this, mut cx| async move { if let Some(paths) = paths.recv().await.flatten() { let results = this - .update(&mut cx, |this, cx| this.open_paths(paths, cx)) + .update(&mut cx, |this, cx| this.open_paths(paths, true, cx)) .await; for result in results { if let Some(result) = result { @@ -1063,17 +1073,22 @@ impl Workspace { fn project_path_for_path( &self, abs_path: &Path, + visible: bool, cx: &mut ViewContext, - ) -> Task> { + ) -> Task, ProjectPath)>> { let entry = self.project().update(cx, |project, cx| { - project.find_or_create_local_worktree(abs_path, true, cx) + project.find_or_create_local_worktree(abs_path, visible, cx) }); cx.spawn(|_, cx| async move { let (worktree, path) = entry.await?; - Ok(ProjectPath { - worktree_id: worktree.read_with(&cx, |t, _| t.id()), - path: path.into(), - }) + let worktree_id = worktree.read_with(&cx, |t, _| t.id()); + Ok(( + worktree, + ProjectPath { + worktree_id, + path: path.into(), + }, + )) }) } @@ -2444,7 +2459,9 @@ pub fn open_paths( }; let items = workspace - .update(&mut cx, |workspace, cx| workspace.open_paths(abs_paths, cx)) + .update(&mut cx, |workspace, cx| { + workspace.open_paths(abs_paths, true, cx) + }) .await; if let Some(project) = new_project { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 8a56777df42247e7371106ff29afc095e6133ddc..1c11aef5f5dbc212945348538f1a74c183224c97 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -322,7 +322,7 @@ fn open_config_file( workspace .update(&mut cx, |workspace, cx| { if workspace.project().read(cx).is_local() { - workspace.open_paths(vec![path.to_path_buf()], cx) + workspace.open_paths(vec![path.to_path_buf()], false, cx) } else { let (_, workspace) = cx.add_window((app_state.build_window_options)(), |cx| { let mut workspace = Workspace::new( @@ -341,7 +341,7 @@ fn open_config_file( workspace }); workspace.update(cx, |workspace, cx| { - workspace.open_paths(vec![path.to_path_buf()], cx) + workspace.open_paths(vec![path.to_path_buf()], false, cx) }) } }) @@ -576,6 +576,7 @@ mod tests { fs.insert_file("/dir1/a.txt", "".into()).await; fs.insert_file("/dir2/b.txt", "".into()).await; fs.insert_file("/dir3/c.txt", "".into()).await; + fs.insert_file("/d.txt", "".into()).await; let project = Project::test(app_state.fs.clone(), ["/dir1".as_ref()], cx).await; let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); @@ -583,7 +584,7 @@ mod tests { // Open a file within an existing worktree. cx.update(|cx| { workspace.update(cx, |view, cx| { - view.open_paths(vec!["/dir1/a.txt".into()], cx) + view.open_paths(vec!["/dir1/a.txt".into()], true, cx) }) }) .await; @@ -607,7 +608,7 @@ mod tests { // Open a file outside of any existing worktree. cx.update(|cx| { workspace.update(cx, |view, cx| { - view.open_paths(vec!["/dir2/b.txt".into()], cx) + view.open_paths(vec!["/dir2/b.txt".into()], true, cx) }) }) .await; @@ -643,7 +644,7 @@ mod tests { // Ensure opening a directory and one of its children only adds one worktree. cx.update(|cx| { workspace.update(cx, |view, cx| { - view.open_paths(vec!["/dir3".into(), "/dir3/c.txt".into()], cx) + view.open_paths(vec!["/dir3".into(), "/dir3/c.txt".into()], true, cx) }) }) .await; @@ -675,6 +676,56 @@ mod tests { "c.txt" ); }); + + // Ensure opening invisibly a file outside an existing worktree adds a new, invisible worktree. + cx.update(|cx| { + workspace.update(cx, |view, cx| { + view.open_paths(vec!["/d.txt".into()], false, cx) + }) + }) + .await; + cx.read(|cx| { + let worktree_roots = workspace + .read(cx) + .worktrees(cx) + .map(|w| w.read(cx).as_local().unwrap().abs_path().as_ref()) + .collect::>(); + assert_eq!( + worktree_roots, + vec!["/dir1", "/dir2/b.txt", "/dir3", "/d.txt"] + .into_iter() + .map(Path::new) + .collect(), + ); + + let visible_worktree_roots = workspace + .read(cx) + .visible_worktrees(cx) + .map(|w| w.read(cx).as_local().unwrap().abs_path().as_ref()) + .collect::>(); + assert_eq!( + visible_worktree_roots, + vec!["/dir1", "/dir2/b.txt", "/dir3"] + .into_iter() + .map(Path::new) + .collect(), + ); + + assert_eq!( + workspace + .read(cx) + .active_pane() + .read(cx) + .active_item() + .unwrap() + .to_any() + .downcast::() + .unwrap() + .read(cx) + .title(cx), + "d.txt" + ); + }); } #[gpui::test] @@ -692,7 +743,7 @@ mod tests { // Open a file within an existing worktree. cx.update(|cx| { workspace.update(cx, |view, cx| { - view.open_paths(vec![PathBuf::from("/root/a.txt")], cx) + view.open_paths(vec![PathBuf::from("/root/a.txt")], true, cx) }) }) .await; From 68093342e7585dc5744e2695ea95c6b4373dc131 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 14 Jun 2022 15:15:23 +0200 Subject: [PATCH 2/3] Broadcast only visible worktree root names --- crates/client/src/user.rs | 6 +++--- crates/collab/src/integration_tests.rs | 20 +++++++++++++------ crates/collab/src/rpc/store.rs | 3 ++- crates/contacts_panel/src/contacts_panel.rs | 22 +++++++++++---------- crates/rpc/proto/zed.proto | 2 +- crates/workspace/src/waiting_room.rs | 4 ++-- 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index c84af7c9f860dae24cc7f9758773430188ba8648..3dc573a8a3aa4bf72866104ce13195ceac9859d7 100644 --- a/crates/client/src/user.rs +++ b/crates/client/src/user.rs @@ -45,7 +45,7 @@ pub struct Contact { #[derive(Clone, Debug, PartialEq)] pub struct ProjectMetadata { pub id: u64, - pub worktree_root_names: Vec, + pub visible_worktree_root_names: Vec, pub guests: BTreeSet>, } @@ -634,7 +634,7 @@ impl Contact { } projects.push(ProjectMetadata { id: project.id, - worktree_root_names: project.worktree_root_names.clone(), + visible_worktree_root_names: project.visible_worktree_root_names.clone(), guests, }); } @@ -648,7 +648,7 @@ impl Contact { pub fn non_empty_projects(&self) -> impl Iterator { self.projects .iter() - .filter(|project| !project.worktree_root_names.is_empty()) + .filter(|project| !project.visible_worktree_root_names.is_empty()) } } diff --git a/crates/collab/src/integration_tests.rs b/crates/collab/src/integration_tests.rs index cf9e7ec8a72e53edcce7cf77452052564fd67982..dd4b85731a40a3b796539ba7f988a25794c29600 100644 --- a/crates/collab/src/integration_tests.rs +++ b/crates/collab/src/integration_tests.rs @@ -608,7 +608,7 @@ async fn test_offline_projects( store.contacts()[0].projects, &[ProjectMetadata { id: project_id, - worktree_root_names: vec!["crate1".into(), "crate2".into()], + visible_worktree_root_names: vec!["crate1".into(), "crate2".into()], guests: Default::default(), }] ); @@ -637,7 +637,7 @@ async fn test_offline_projects( store.contacts()[0].projects, &[ProjectMetadata { id: project_id, - worktree_root_names: vec!["crate1".into(), "crate2".into()], + visible_worktree_root_names: vec!["crate1".into(), "crate2".into()], guests: Default::default(), }] ); @@ -655,7 +655,11 @@ async fn test_offline_projects( store.contacts()[0].projects, &[ProjectMetadata { id: project_id, - worktree_root_names: vec!["crate1".into(), "crate2".into(), "crate3".into()], + visible_worktree_root_names: vec![ + "crate1".into(), + "crate2".into(), + "crate3".into() + ], guests: Default::default(), }] ); @@ -695,12 +699,16 @@ async fn test_offline_projects( &[ ProjectMetadata { id: project_id, - worktree_root_names: vec!["crate1".into(), "crate2".into(), "crate3".into()], + visible_worktree_root_names: vec![ + "crate1".into(), + "crate2".into(), + "crate3".into() + ], guests: Default::default(), }, ProjectMetadata { id: project2_id, - worktree_root_names: vec!["crate3".into()], + visible_worktree_root_names: vec!["crate3".into()], guests: Default::default(), } ] @@ -3515,7 +3523,7 @@ async fn test_contacts( .iter() .map(|p| { ( - p.worktree_root_names[0].as_str(), + p.visible_worktree_root_names[0].as_str(), p.guests.iter().map(|p| p.github_login.as_str()).collect(), ) }) diff --git a/crates/collab/src/rpc/store.rs b/crates/collab/src/rpc/store.rs index 857f3515170b7f2041e06499b25276680d80302c..d929078dc5f9c1f41660aac4d322caacda653abc 100644 --- a/crates/collab/src/rpc/store.rs +++ b/crates/collab/src/rpc/store.rs @@ -277,9 +277,10 @@ impl Store { if project.host_user_id == user_id { metadata.push(proto::ProjectMetadata { id: project_id, - worktree_root_names: project + visible_worktree_root_names: project .worktrees .values() + .filter(|worktree| worktree.visible) .map(|worktree| worktree.root_name.clone()) .collect(), guests: project diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index e1838f9a1cb9aef17e56a0c0d8c1dd5c8ffcbdf1..a21a9d98ab64c1e5f7b74e6716ed5e2808caaddb 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/crates/contacts_panel/src/contacts_panel.rs @@ -462,7 +462,7 @@ impl ContactsPanel { ) .with_child( Label::new( - project.worktree_root_names.join(", "), + project.visible_worktree_root_names.join(", "), row.name.text.clone(), ) .aligned() @@ -847,7 +847,7 @@ impl ContactsPanel { p.read(cx).remote_id() == Some(project.id) }) .map(|ix| open_projects.remove(ix).downgrade()); - if project.worktree_root_names.is_empty() { + if project.visible_worktree_root_names.is_empty() { None } else { Some(ContactEntry::ContactProject( @@ -872,7 +872,7 @@ impl ContactsPanel { self.entries.extend( contact.projects.iter().enumerate().filter_map( |(ix, project)| { - if project.worktree_root_names.is_empty() { + if project.visible_worktree_root_names.is_empty() { None } else { Some(ContactEntry::ContactProject( @@ -1295,7 +1295,7 @@ mod tests { should_notify: false, projects: vec![proto::ProjectMetadata { id: 101, - worktree_root_names: vec!["dir1".to_string()], + visible_worktree_root_names: vec!["dir1".to_string()], guests: vec![2], }], }, @@ -1305,7 +1305,7 @@ mod tests { should_notify: false, projects: vec![proto::ProjectMetadata { id: 102, - worktree_root_names: vec!["dir2".to_string()], + visible_worktree_root_names: vec!["dir2".to_string()], guests: vec![2], }], }, @@ -1321,7 +1321,7 @@ mod tests { should_notify: false, projects: vec![proto::ProjectMetadata { id: 103, - worktree_root_names: vec!["dir3".to_string()], + visible_worktree_root_names: vec!["dir3".to_string()], guests: vec![3], }], }, @@ -1425,12 +1425,12 @@ mod tests { projects: vec![ proto::ProjectMetadata { id: 103, - worktree_root_names: vec!["dir3".to_string()], + visible_worktree_root_names: vec!["dir3".to_string()], guests: vec![3], }, proto::ProjectMetadata { id: 200, - worktree_root_names: vec!["private_dir".to_string()], + visible_worktree_root_names: vec!["private_dir".to_string()], guests: vec![3], }, ], @@ -1489,7 +1489,7 @@ mod tests { should_notify: false, projects: vec![proto::ProjectMetadata { id: 103, - worktree_root_names: vec!["dir3".to_string()], + visible_worktree_root_names: vec!["dir3".to_string()], guests: vec![3], }], }], @@ -1611,7 +1611,9 @@ mod tests { .map(|project| project.read(cx)); format!( " {}{}", - contact.projects[*project_ix].worktree_root_names.join(", "), + contact.projects[*project_ix] + .visible_worktree_root_names + .join(", "), if project.map_or(true, |project| project.is_online()) { "" } else { diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 7bece4c93cca486a97593c03e99bb0448fb32af5..ff52fb9e8d6f512904fc5d8535c6e9dc127d5e21 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -946,7 +946,7 @@ message Contact { message ProjectMetadata { uint64 id = 1; - repeated string worktree_root_names = 3; + repeated string visible_worktree_root_names = 3; repeated uint64 guests = 4; } diff --git a/crates/workspace/src/waiting_room.rs b/crates/workspace/src/waiting_room.rs index c3d1e3c7e6925f50475ae4bfa5042fe27671c9b1..5052afcf50df693850981eb940ac349bec34cc43 100644 --- a/crates/workspace/src/waiting_room.rs +++ b/crates/workspace/src/waiting_room.rs @@ -137,7 +137,7 @@ impl WaitingRoom { login, humanize_list( &contact.projects[project_index] - .worktree_root_names + .visible_worktree_root_names ) ) } @@ -166,7 +166,7 @@ impl WaitingRoom { message: format!( "Asking to join @{}'s copy of {}...", contact.user.github_login, - humanize_list(&contact.projects[project_index].worktree_root_names) + humanize_list(&contact.projects[project_index].visible_worktree_root_names) ), waiting: true, client, From f89977ba41ff41e1a4a997d01cc095c6f69baff2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 14 Jun 2022 15:21:37 +0200 Subject: [PATCH 3/3] Bump protocol version --- crates/rpc/src/rpc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rpc/src/rpc.rs b/crates/rpc/src/rpc.rs index df50b16aa102c83d11d98ec049fa83e55fa3e87d..ae39b44fd509ddce89d3a4c415764e12a467e7e5 100644 --- a/crates/rpc/src/rpc.rs +++ b/crates/rpc/src/rpc.rs @@ -6,4 +6,4 @@ pub use conn::Connection; pub use peer::*; mod macros; -pub const PROTOCOL_VERSION: u32 = 23; +pub const PROTOCOL_VERSION: u32 = 24;