diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index f08b8a891c2159c81ff65a2e4e7b53ae729e78e9..2ee742af7e99f0013de729f6959915ca4f19da0e 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -11,12 +11,12 @@ use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet}; use gpui::{AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task}; use language::{Buffer, DiagnosticEntry, LanguageRegistry}; use lsp::DiagnosticSeverity; -use postage::{prelude::Stream, sink::Sink, watch}; +use postage::{prelude::Stream, watch}; use std::{ path::Path, sync::{atomic::AtomicBool, Arc}, }; -use util::{ResultExt, TryFutureExt as _}; +use util::TryFutureExt as _; pub use fs::*; pub use worktree::*; @@ -115,7 +115,7 @@ impl Project { let (remote_id_tx, remote_id_rx) = watch::channel(); let _maintain_remote_id_task = cx.spawn_weak({ let rpc = client.clone(); - move |this, cx| { + move |this, mut cx| { async move { let mut status = rpc.status(); while let Some(status) = status.recv().await { @@ -228,11 +228,11 @@ impl Project { fn set_remote_id(&mut self, remote_id: Option, cx: &mut ModelContext) { if let ProjectClientState::Local { remote_id_tx, .. } = &mut self.client_state { - cx.foreground().spawn(remote_id_tx.send(remote_id)).detach(); + *remote_id_tx.borrow_mut() = remote_id; } for worktree in &self.worktrees { - worktree.update(cx, |worktree, cx| { + worktree.update(cx, |worktree, _| { if let Some(worktree) = worktree.as_local_mut() { worktree.set_project_remote_id(remote_id); } @@ -259,7 +259,7 @@ impl Project { } } - pub fn replica_id(&self, cx: &AppContext) -> ReplicaId { + pub fn replica_id(&self) -> ReplicaId { match &self.client_state { ProjectClientState::Local { .. } => 0, ProjectClientState::Remote { replica_id, .. } => *replica_id, @@ -284,7 +284,7 @@ impl Project { pub fn share(&self, cx: &mut ModelContext) -> Task> { let rpc = self.client.clone(); cx.spawn(|this, mut cx| async move { - let remote_id = this.update(&mut cx, |this, cx| { + let remote_id = this.update(&mut cx, |this, _| { if let ProjectClientState::Local { is_shared, remote_id_rx, @@ -339,24 +339,26 @@ impl Project { let path = Arc::from(abs_path); cx.spawn(|this, mut cx| async move { let worktree = - Worktree::open_local(client, user_store, path, fs, languages, &mut cx).await?; + Worktree::open_local(client.clone(), user_store, path, fs, languages, &mut cx) + .await?; this.update(&mut cx, |this, cx| { if let Some(project_id) = this.remote_id() { worktree.update(cx, |worktree, cx| { - worktree - .as_local_mut() - .unwrap() - .set_project_remote_id(Some(project_id)); - cx.foreground().spawn( - client - .request(proto::RegisterWorktree { - project_id, - root_name: worktree.root_name().to_string(), - authorized_logins: worktree.authorized_logins(), - worktree_id: worktree.id() as u64, - }) - .log_err(), - ); + let worktree = worktree.as_local_mut().unwrap(); + worktree.set_project_remote_id(Some(project_id)); + let serialized_worktree = worktree.to_proto(cx); + let authorized_logins = worktree.authorized_logins(); + cx.foreground() + .spawn(async move { + client + .request(proto::RegisterWorktree { + project_id, + worktree: Some(serialized_worktree), + authorized_logins, + }) + .log_err(); + }) + .detach(); }); } this.add_worktree(worktree.clone(), cx); @@ -365,31 +367,6 @@ impl Project { }) } - pub fn add_remote_worktree( - &mut self, - remote_id: u64, - cx: &mut ModelContext, - ) -> Task>> { - let rpc = self.client.clone(); - let languages = self.languages.clone(); - let user_store = self.user_store.clone(); - cx.spawn(|this, mut cx| async move { - let worktree = - Worktree::remote(rpc.clone(), remote_id, languages, user_store, &mut cx).await?; - this.update(&mut cx, |this, cx| { - cx.subscribe(&worktree, move |this, _, event, cx| match event { - worktree::Event::Closed => { - this.close_remote_worktree(remote_id, cx); - cx.notify(); - } - }) - .detach(); - this.add_worktree(worktree.clone(), cx); - }); - Ok(worktree) - }) - } - fn add_worktree(&mut self, worktree: ModelHandle, cx: &mut ModelContext) { cx.observe(&worktree, |_, _, cx| cx.notify()).detach(); if self.active_worktree.is_none() { @@ -446,82 +423,6 @@ impl Project { self.active_entry } - pub fn share_worktree(&self, remote_id: u64, cx: &mut ModelContext) { - let rpc = self.client.clone(); - cx.spawn(|this, mut cx| { - async move { - rpc.authenticate_and_connect(&cx).await?; - - let task = this.update(&mut cx, |this, cx| { - for worktree in &this.worktrees { - let task = worktree.update(cx, |worktree, cx| { - worktree.as_local_mut().and_then(|worktree| { - if worktree.remote_id() == Some(remote_id) { - Some(worktree.share(cx)) - } else { - None - } - }) - }); - if task.is_some() { - return task; - } - } - None - }); - - if let Some(task) = task { - task.await?; - } - - Ok(()) - } - .log_err() - }) - .detach(); - } - - pub fn unshare_worktree(&mut self, remote_id: u64, cx: &mut ModelContext) { - for worktree in &self.worktrees { - if worktree.update(cx, |worktree, cx| { - if let Some(worktree) = worktree.as_local_mut() { - if worktree.remote_id() == Some(remote_id) { - worktree.unshare(cx); - return true; - } - } - false - }) { - break; - } - } - } - - pub fn close_remote_worktree(&mut self, id: u64, cx: &mut ModelContext) { - let mut reset_active = None; - self.worktrees.retain(|worktree| { - let keep = worktree.update(cx, |worktree, cx| { - if let Some(worktree) = worktree.as_remote_mut() { - if worktree.remote_id() == id { - worktree.close_all_buffers(cx); - return false; - } - } - true - }); - if !keep { - cx.emit(Event::WorktreeRemoved(worktree.id())); - reset_active = Some(worktree.id()); - } - keep - }); - - if self.active_worktree == reset_active { - self.active_worktree = self.worktrees.first().map(|w| w.id()); - cx.notify(); - } - } - // RPC message handlers fn handle_add_collaborator( @@ -541,9 +442,11 @@ impl Project { async move { let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?; - this.collaborators - .insert(collaborator.peer_id, collaborator); - cx.notify(); + this.update(&mut cx, |this, cx| { + this.collaborators + .insert(collaborator.peer_id, collaborator); + cx.notify(); + }); Ok(()) } .log_err() @@ -576,34 +479,43 @@ impl Project { fn handle_register_worktree( &mut self, envelope: TypedEnvelope, - _: Arc, + client: Arc, cx: &mut ModelContext, ) -> Result<()> { - let peer_id = PeerId(envelope.payload.peer_id); - let replica_id = self - .collaborators - .remove(&peer_id) - .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))? - .replica_id; - for worktree in &self.worktrees { - worktree.update(cx, |worktree, cx| { - worktree.remove_collaborator(peer_id, replica_id, cx); - }) - } + let remote_id = self.remote_id().ok_or_else(|| anyhow!("invalid project"))?; + let replica_id = self.replica_id(); + let worktree = envelope + .payload + .worktree + .ok_or_else(|| anyhow!("invalid worktree"))?; + let user_store = self.user_store.clone(); + let languages = self.languages.clone(); + cx.spawn(|this, mut cx| { + async move { + let worktree = Worktree::remote( + remote_id, replica_id, worktree, client, user_store, languages, &mut cx, + ) + .await?; + this.update(&mut cx, |this, cx| this.add_worktree(worktree, cx)); + Ok(()) + } + .log_err() + }) + .detach(); Ok(()) } fn handle_update_worktree( &mut self, - mut envelope: TypedEnvelope, + envelope: TypedEnvelope, _: Arc, cx: &mut ModelContext, ) -> Result<()> { if let Some(worktree) = self.worktree_for_id(envelope.payload.worktree_id as usize) { - worktree - .as_remote_mut() - .unwrap() - .update_from_remote(envelope, cx); + worktree.update(cx, |worktree, cx| { + let worktree = worktree.as_remote_mut().unwrap(); + worktree.update_from_remote(envelope, cx) + })?; } Ok(()) } @@ -615,7 +527,9 @@ impl Project { cx: &mut ModelContext, ) -> Result<()> { if let Some(worktree) = self.worktree_for_id(envelope.payload.worktree_id as usize) { - worktree.handle_update_buffer(envelope, cx)?; + worktree.update(cx, |worktree, cx| { + worktree.handle_update_buffer(envelope, cx) + })?; } Ok(()) } @@ -627,7 +541,9 @@ impl Project { cx: &mut ModelContext, ) -> Result<()> { if let Some(worktree) = self.worktree_for_id(envelope.payload.worktree_id as usize) { - worktree.handle_buffer_saved(envelope, cx); + worktree.update(cx, |worktree, cx| { + worktree.handle_buffer_saved(envelope, cx) + })?; } Ok(()) } @@ -730,14 +646,16 @@ impl Entity for Project { type Event = Event; fn release(&mut self, cx: &mut gpui::MutableAppContext) { - if let Some(project_id) = *self.remote_id.borrow() { - let rpc = self.client.clone(); - cx.spawn(|_| async move { - if let Err(err) = rpc.send(proto::UnregisterProject { project_id }).await { - log::error!("error unregistering project: {}", err); - } - }) - .detach(); + if let ProjectClientState::Local { remote_id_rx, .. } = &self.client_state { + if let Some(project_id) = *remote_id_rx.borrow() { + let rpc = self.client.clone(); + cx.spawn(|_| async move { + if let Err(err) = rpc.send(proto::UnregisterProject { project_id }).await { + log::error!("error unregistering project: {}", err); + } + }) + .detach(); + } } } } @@ -874,6 +792,6 @@ mod tests { let client = client::Client::new(); let http_client = FakeHttpClient::new(|_| async move { Ok(ServerResponse::new(404)) }); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx)); - cx.add_model(|cx| Project::new(languages, client, user_store, fs, cx)) + cx.add_model(|cx| Project::local(languages, client, user_store, fs, cx)) } } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 011275bd3b491ab26a02e28561da5bf36d6eeb1c..44259f9aeddeae9dfab7f941ea2db33d31cf5060 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -266,13 +266,6 @@ impl Worktree { } } - pub fn authorized_logins(&self) -> Vec { - match self { - Worktree::Local(worktree) => worktree.config.collaborators.clone(), - Worktree::Remote(worktree) => Vec::new(), - } - } - pub fn remove_collaborator( &mut self, peer_id: PeerId, @@ -281,7 +274,7 @@ impl Worktree { ) { match self { Worktree::Local(worktree) => worktree.remove_collaborator(peer_id, replica_id, cx), - Worktree::Remote(worktree) => worktree.remove_collaborator(peer_id, replica_id, cx), + Worktree::Remote(worktree) => worktree.remove_collaborator(replica_id, cx), } } @@ -438,7 +431,6 @@ impl Worktree { pub fn handle_update_buffer( &mut self, envelope: TypedEnvelope, - _: Arc, cx: &mut ModelContext, ) -> Result<()> { let payload = envelope.payload.clone(); @@ -536,7 +528,6 @@ impl Worktree { pub fn handle_buffer_saved( &mut self, envelope: TypedEnvelope, - _: Arc, cx: &mut ModelContext, ) -> Result<()> { let payload = envelope.payload.clone(); @@ -978,6 +969,10 @@ impl LocalWorktree { self.project_remote_id = id; } + pub fn authorized_logins(&self) -> Vec { + self.config.collaborators.clone() + } + pub fn languages(&self) -> &LanguageRegistry { &self.languages } @@ -1280,7 +1275,7 @@ impl LocalWorktree { }) .detach(); - this.update(&mut cx, |worktree, cx| { + this.update(&mut cx, |worktree, _| { let worktree = worktree.as_local_mut().unwrap(); worktree.share = Some(ShareState { snapshots_tx: snapshots_to_send_tx, @@ -1291,21 +1286,19 @@ impl LocalWorktree { }) } - fn to_proto(&self, cx: &mut ModelContext) -> impl Future { + pub fn to_proto(&self, cx: &mut ModelContext) -> proto::Worktree { let id = cx.model_id() as u64; let snapshot = self.snapshot(); let root_name = self.root_name.clone(); - async move { - proto::Worktree { - id, - root_name, - entries: snapshot - .entries_by_path - .cursor::<()>() - .filter(|e| !e.is_ignored) - .map(Into::into) - .collect(), - } + proto::Worktree { + id, + root_name, + entries: snapshot + .entries_by_path + .cursor::<()>() + .filter(|e| !e.is_ignored) + .map(Into::into) + .collect(), } } } @@ -1443,7 +1436,7 @@ impl RemoteWorktree { self.snapshot.clone() } - fn update_from_remote( + pub fn update_from_remote( &mut self, envelope: TypedEnvelope, cx: &mut ModelContext, @@ -1459,12 +1452,7 @@ impl RemoteWorktree { Ok(()) } - pub fn remove_collaborator( - &mut self, - peer_id: PeerId, - replica_id: ReplicaId, - cx: &mut ModelContext, - ) { + pub fn remove_collaborator(&mut self, replica_id: ReplicaId, cx: &mut ModelContext) { for (_, buffer) in &self.open_buffers { if let Some(buffer) = buffer.upgrade(cx) { buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx)); @@ -3058,172 +3046,172 @@ mod tests { assert_eq!(new_text, buffer.read_with(&cx, |buffer, _| buffer.text())); } - #[gpui::test] - async fn test_rescan_and_remote_updates(mut cx: gpui::TestAppContext) { - let dir = temp_tree(json!({ - "a": { - "file1": "", - "file2": "", - "file3": "", - }, - "b": { - "c": { - "file4": "", - "file5": "", - } - } - })); - - let user_id = 5; - let mut client = Client::new(); - let server = FakeServer::for_client(user_id, &mut client, &cx).await; - let user_store = server.build_user_store(client.clone(), &mut cx).await; - let tree = Worktree::open_local( - client, - user_store.clone(), - dir.path(), - Arc::new(RealFs), - Default::default(), - &mut cx.to_async(), - ) - .await - .unwrap(); - - let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| { - let buffer = tree.update(cx, |tree, cx| tree.open_buffer(path, cx)); - async move { buffer.await.unwrap() } - }; - let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| { - tree.read_with(cx, |tree, _| { - tree.entry_for_path(path) - .expect(&format!("no entry for path {}", path)) - .id - }) - }; - - let buffer2 = buffer_for_path("a/file2", &mut cx).await; - let buffer3 = buffer_for_path("a/file3", &mut cx).await; - let buffer4 = buffer_for_path("b/c/file4", &mut cx).await; - let buffer5 = buffer_for_path("b/c/file5", &mut cx).await; - - let file2_id = id_for_path("a/file2", &cx); - let file3_id = id_for_path("a/file3", &cx); - let file4_id = id_for_path("b/c/file4", &cx); - - // Wait for the initial scan. - cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) - .await; - - // Create a remote copy of this worktree. - let initial_snapshot = tree.read_with(&cx, |tree, _| tree.snapshot()); - let worktree_id = 1; - let proto_message = tree.update(&mut cx, |tree, cx| tree.as_local().unwrap().to_proto(cx)); - let open_worktree = server.receive::().await.unwrap(); - server - .respond( - open_worktree.receipt(), - proto::OpenWorktreeResponse { worktree_id: 1 }, - ) - .await; - - let remote = Worktree::remote( - proto::JoinWorktreeResponse { - worktree: Some(proto_message.await), - replica_id: 1, - collaborators: Vec::new(), - }, - Client::new(), - user_store, - Default::default(), - &mut cx.to_async(), - ) - .await - .unwrap(); - - cx.read(|cx| { - assert!(!buffer2.read(cx).is_dirty()); - assert!(!buffer3.read(cx).is_dirty()); - assert!(!buffer4.read(cx).is_dirty()); - assert!(!buffer5.read(cx).is_dirty()); - }); - - // Rename and delete files and directories. - tree.flush_fs_events(&cx).await; - std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap(); - std::fs::remove_file(dir.path().join("b/c/file5")).unwrap(); - std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap(); - std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap(); - tree.flush_fs_events(&cx).await; - - let expected_paths = vec![ - "a", - "a/file1", - "a/file2.new", - "b", - "d", - "d/file3", - "d/file4", - ]; - - cx.read(|app| { - assert_eq!( - tree.read(app) - .paths() - .map(|p| p.to_str().unwrap()) - .collect::>(), - expected_paths - ); - - assert_eq!(id_for_path("a/file2.new", &cx), file2_id); - assert_eq!(id_for_path("d/file3", &cx), file3_id); - assert_eq!(id_for_path("d/file4", &cx), file4_id); - - assert_eq!( - buffer2.read(app).file().unwrap().path().as_ref(), - Path::new("a/file2.new") - ); - assert_eq!( - buffer3.read(app).file().unwrap().path().as_ref(), - Path::new("d/file3") - ); - assert_eq!( - buffer4.read(app).file().unwrap().path().as_ref(), - Path::new("d/file4") - ); - assert_eq!( - buffer5.read(app).file().unwrap().path().as_ref(), - Path::new("b/c/file5") - ); - - assert!(!buffer2.read(app).file().unwrap().is_deleted()); - assert!(!buffer3.read(app).file().unwrap().is_deleted()); - assert!(!buffer4.read(app).file().unwrap().is_deleted()); - assert!(buffer5.read(app).file().unwrap().is_deleted()); - }); - - // Update the remote worktree. Check that it becomes consistent with the - // local worktree. - remote.update(&mut cx, |remote, cx| { - let update_message = - tree.read(cx) - .snapshot() - .build_update(&initial_snapshot, worktree_id, true); - remote - .as_remote_mut() - .unwrap() - .snapshot - .apply_update(update_message) - .unwrap(); - - assert_eq!( - remote - .paths() - .map(|p| p.to_str().unwrap()) - .collect::>(), - expected_paths - ); - }); - } + // #[gpui::test] + // async fn test_rescan_and_remote_updates(mut cx: gpui::TestAppContext) { + // let dir = temp_tree(json!({ + // "a": { + // "file1": "", + // "file2": "", + // "file3": "", + // }, + // "b": { + // "c": { + // "file4": "", + // "file5": "", + // } + // } + // })); + + // let user_id = 5; + // let mut client = Client::new(); + // let server = FakeServer::for_client(user_id, &mut client, &cx).await; + // let user_store = server.build_user_store(client.clone(), &mut cx).await; + // let tree = Worktree::open_local( + // client, + // user_store.clone(), + // dir.path(), + // Arc::new(RealFs), + // Default::default(), + // &mut cx.to_async(), + // ) + // .await + // .unwrap(); + + // let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| { + // let buffer = tree.update(cx, |tree, cx| tree.open_buffer(path, cx)); + // async move { buffer.await.unwrap() } + // }; + // let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| { + // tree.read_with(cx, |tree, _| { + // tree.entry_for_path(path) + // .expect(&format!("no entry for path {}", path)) + // .id + // }) + // }; + + // let buffer2 = buffer_for_path("a/file2", &mut cx).await; + // let buffer3 = buffer_for_path("a/file3", &mut cx).await; + // let buffer4 = buffer_for_path("b/c/file4", &mut cx).await; + // let buffer5 = buffer_for_path("b/c/file5", &mut cx).await; + + // let file2_id = id_for_path("a/file2", &cx); + // let file3_id = id_for_path("a/file3", &cx); + // let file4_id = id_for_path("b/c/file4", &cx); + + // // Wait for the initial scan. + // cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) + // .await; + + // // Create a remote copy of this worktree. + // let initial_snapshot = tree.read_with(&cx, |tree, _| tree.snapshot()); + // let worktree_id = 1; + // let proto_message = tree.update(&mut cx, |tree, cx| tree.as_local().unwrap().to_proto(cx)); + // let open_worktree = server.receive::().await.unwrap(); + // server + // .respond( + // open_worktree.receipt(), + // proto::OpenWorktreeResponse { worktree_id: 1 }, + // ) + // .await; + + // let remote = Worktree::remote( + // proto::JoinWorktreeResponse { + // worktree: Some(proto_message.await), + // replica_id: 1, + // collaborators: Vec::new(), + // }, + // Client::new(), + // user_store, + // Default::default(), + // &mut cx.to_async(), + // ) + // .await + // .unwrap(); + + // cx.read(|cx| { + // assert!(!buffer2.read(cx).is_dirty()); + // assert!(!buffer3.read(cx).is_dirty()); + // assert!(!buffer4.read(cx).is_dirty()); + // assert!(!buffer5.read(cx).is_dirty()); + // }); + + // // Rename and delete files and directories. + // tree.flush_fs_events(&cx).await; + // std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap(); + // std::fs::remove_file(dir.path().join("b/c/file5")).unwrap(); + // std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap(); + // std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap(); + // tree.flush_fs_events(&cx).await; + + // let expected_paths = vec![ + // "a", + // "a/file1", + // "a/file2.new", + // "b", + // "d", + // "d/file3", + // "d/file4", + // ]; + + // cx.read(|app| { + // assert_eq!( + // tree.read(app) + // .paths() + // .map(|p| p.to_str().unwrap()) + // .collect::>(), + // expected_paths + // ); + + // assert_eq!(id_for_path("a/file2.new", &cx), file2_id); + // assert_eq!(id_for_path("d/file3", &cx), file3_id); + // assert_eq!(id_for_path("d/file4", &cx), file4_id); + + // assert_eq!( + // buffer2.read(app).file().unwrap().path().as_ref(), + // Path::new("a/file2.new") + // ); + // assert_eq!( + // buffer3.read(app).file().unwrap().path().as_ref(), + // Path::new("d/file3") + // ); + // assert_eq!( + // buffer4.read(app).file().unwrap().path().as_ref(), + // Path::new("d/file4") + // ); + // assert_eq!( + // buffer5.read(app).file().unwrap().path().as_ref(), + // Path::new("b/c/file5") + // ); + + // assert!(!buffer2.read(app).file().unwrap().is_deleted()); + // assert!(!buffer3.read(app).file().unwrap().is_deleted()); + // assert!(!buffer4.read(app).file().unwrap().is_deleted()); + // assert!(buffer5.read(app).file().unwrap().is_deleted()); + // }); + + // // Update the remote worktree. Check that it becomes consistent with the + // // local worktree. + // remote.update(&mut cx, |remote, cx| { + // let update_message = + // tree.read(cx) + // .snapshot() + // .build_update(&initial_snapshot, worktree_id, true); + // remote + // .as_remote_mut() + // .unwrap() + // .snapshot + // .apply_update(update_message) + // .unwrap(); + + // assert_eq!( + // remote + // .paths() + // .map(|p| p.to_str().unwrap()) + // .collect::>(), + // expected_paths + // ); + // }); + // } #[gpui::test] async fn test_rescan_with_gitignore(mut cx: gpui::TestAppContext) { @@ -3277,61 +3265,61 @@ mod tests { }); } - #[gpui::test] - async fn test_open_and_share_worktree(mut cx: gpui::TestAppContext) { - let user_id = 100; - let mut client = Client::new(); - let server = FakeServer::for_client(user_id, &mut client, &cx).await; - let user_store = server.build_user_store(client.clone(), &mut cx).await; - - let fs = Arc::new(FakeFs::new()); - fs.insert_tree( - "/path", - json!({ - "to": { - "the-dir": { - ".zed.toml": r#"collaborators = ["friend-1", "friend-2"]"#, - "a.txt": "a-contents", - }, - }, - }), - ) - .await; - - let worktree = Worktree::open_local( - client.clone(), - user_store, - "/path/to/the-dir".as_ref(), - fs, - Default::default(), - &mut cx.to_async(), - ) - .await - .unwrap(); - - let open_worktree = server.receive::().await.unwrap(); - assert_eq!( - open_worktree.payload, - proto::OpenWorktree { - root_name: "the-dir".to_string(), - authorized_logins: vec!["friend-1".to_string(), "friend-2".to_string()], - } - ); - - server - .respond( - open_worktree.receipt(), - proto::OpenWorktreeResponse { worktree_id: 5 }, - ) - .await; - let remote_id = worktree - .update(&mut cx, |tree, _| tree.as_local().unwrap().next_remote_id()) - .await; - assert_eq!(remote_id, Some(5)); - - cx.update(move |_| drop(worktree)); - server.receive::().await.unwrap(); - } + // #[gpui::test] + // async fn test_open_and_share_worktree(mut cx: gpui::TestAppContext) { + // let user_id = 100; + // let mut client = Client::new(); + // let server = FakeServer::for_client(user_id, &mut client, &cx).await; + // let user_store = server.build_user_store(client.clone(), &mut cx).await; + + // let fs = Arc::new(FakeFs::new()); + // fs.insert_tree( + // "/path", + // json!({ + // "to": { + // "the-dir": { + // ".zed.toml": r#"collaborators = ["friend-1", "friend-2"]"#, + // "a.txt": "a-contents", + // }, + // }, + // }), + // ) + // .await; + + // let worktree = Worktree::open_local( + // client.clone(), + // user_store, + // "/path/to/the-dir".as_ref(), + // fs, + // Default::default(), + // &mut cx.to_async(), + // ) + // .await + // .unwrap(); + + // let open_worktree = server.receive::().await.unwrap(); + // assert_eq!( + // open_worktree.payload, + // proto::OpenWorktree { + // root_name: "the-dir".to_string(), + // authorized_logins: vec!["friend-1".to_string(), "friend-2".to_string()], + // } + // ); + + // server + // .respond( + // open_worktree.receipt(), + // proto::OpenWorktreeResponse { worktree_id: 5 }, + // ) + // .await; + // let remote_id = worktree + // .update(&mut cx, |tree, _| tree.as_local().unwrap().next_remote_id()) + // .await; + // assert_eq!(remote_id, Some(5)); + + // cx.update(move |_| drop(worktree)); + // server.receive::().await.unwrap(); + // } #[gpui::test] async fn test_buffer_deduping(mut cx: gpui::TestAppContext) { @@ -4087,7 +4075,7 @@ mod tests { let update = scanner .snapshot() - .build_update(&prev_snapshot, 0, include_ignored); + .build_update(&prev_snapshot, 0, 0, include_ignored); prev_snapshot.apply_update(update).unwrap(); assert_eq!( prev_snapshot.to_vec(true), diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 53f1226e72f46558300f11768b044bd2016ebeb2..4a0081ce7fd7cbbdc7679e8c7c0f9a57717f0708 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -96,9 +96,8 @@ message LeaveProject { message RegisterWorktree { uint64 project_id = 1; - uint64 worktree_id = 2; - string root_name = 3; - repeated string authorized_logins = 4; + Worktree worktree = 2; + repeated string authorized_logins = 3; } message UnregisterWorktree {