From 89d25458ac58ea842d760ea8d0fec1790762ea52 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 18 Jun 2021 14:52:38 +0200 Subject: [PATCH] Add worktree to workspace when joining a remote worktree --- zed-rpc/proto/zed.proto | 11 ++++++- zed-rpc/src/peer.rs | 30 ++++++++--------- zed-rpc/src/proto.rs | 7 ++-- zed/src/workspace.rs | 12 +++++-- zed/src/worktree.rs | 72 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 103 insertions(+), 29 deletions(-) diff --git a/zed-rpc/proto/zed.proto b/zed-rpc/proto/zed.proto index c64a5abd0596b1ad32b4d38b9672c93e064443e6..522ab451d0f746c17e8001edb7fdfa327fdc69db 100644 --- a/zed-rpc/proto/zed.proto +++ b/zed-rpc/proto/zed.proto @@ -53,7 +53,16 @@ message OpenBufferResponse { } message Worktree { - repeated string paths = 1; + string root_name = 1; + repeated Entry entries = 2; +} + +message Entry { + bool is_dir = 1; + string path = 2; + uint64 inode = 3; + bool is_symlink = 4; + bool is_ignored = 5; } message Buffer { diff --git a/zed-rpc/src/peer.rs b/zed-rpc/src/peer.rs index dec6ef95334b29ff0488627681c1dff3a3f7fcb7..4c23060a5cc2e3787fbc07c34a836661a2e89d0d 100644 --- a/zed-rpc/src/peer.rs +++ b/zed-rpc/src/peer.rs @@ -341,23 +341,19 @@ mod tests { smol::spawn(server.handle_messages(server_conn_id2)).detach(); // define the expected requests and responses - let request1 = proto::OpenWorktree { - worktree_id: 101, - access_token: "first-worktree-access-token".to_string(), + let request1 = proto::Auth { + user_id: 1, + access_token: "token-1".to_string(), }; - let response1 = proto::OpenWorktreeResponse { - worktree: Some(proto::Worktree { - paths: vec!["path/one".to_string()], - }), + let response1 = proto::AuthResponse { + credentials_valid: true, }; - let request2 = proto::OpenWorktree { - worktree_id: 102, - access_token: "second-worktree-access-token".to_string(), + let request2 = proto::Auth { + user_id: 2, + access_token: "token-2".to_string(), }; - let response2 = proto::OpenWorktreeResponse { - worktree: Some(proto::Worktree { - paths: vec!["path/two".to_string(), "path/three".to_string()], - }), + let response2 = proto::AuthResponse { + credentials_valid: false, }; let request3 = proto::OpenBuffer { worktree_id: 102, @@ -386,7 +382,7 @@ mod tests { // on the server, respond to two requests for each client let mut open_buffer_rx = server.add_message_handler::().await; - let mut open_worktree_rx = server.add_message_handler::().await; + let mut auth_rx = server.add_message_handler::().await; let (mut server_done_tx, mut server_done_rx) = oneshot::channel::<()>(); smol::spawn({ let request1 = request1.clone(); @@ -398,11 +394,11 @@ mod tests { let response3 = response3.clone(); let response4 = response4.clone(); async move { - let msg = open_worktree_rx.recv().await.unwrap(); + let msg = auth_rx.recv().await.unwrap(); assert_eq!(msg.payload, request1); server.respond(msg, response1.clone()).await.unwrap(); - let msg = open_worktree_rx.recv().await.unwrap(); + let msg = auth_rx.recv().await.unwrap(); assert_eq!(msg.payload, request2.clone()); server.respond(msg, response2.clone()).await.unwrap(); diff --git a/zed-rpc/src/proto.rs b/zed-rpc/src/proto.rs index a44576128bb00682cb07c0fb2c253f1c1966343d..62f987c06a0f9fef0b23fe125af85e360b39550a 100644 --- a/zed-rpc/src/proto.rs +++ b/zed-rpc/src/proto.rs @@ -132,10 +132,9 @@ mod tests { } .into_envelope(3, None); - let message2 = ShareWorktree { - worktree: Some(Worktree { - paths: vec!["ok".to_string()], - }), + let message2 = OpenBuffer { + worktree_id: 1, + path: "path".to_string(), } .into_envelope(5, None); diff --git a/zed/src/workspace.rs b/zed/src/workspace.rs index 4fda4cacd3b93fe9a336c107084797246c2b1c35..5308cc582f544ce7cc6e0d829c06d73bbda1feb6 100644 --- a/zed/src/workspace.rs +++ b/zed/src/workspace.rs @@ -705,7 +705,7 @@ impl Workspace { let rpc = self.rpc.clone(); let executor = cx.background_executor().clone(); - let task = cx.spawn(|_, cx| async move { + let task = cx.spawn(|this, mut cx| async move { let connection_id = rpc.connect_to_server(&cx, &executor).await?; let worktree_url = cx @@ -725,7 +725,15 @@ impl Workspace { }, ) .await?; - log::info!("joined worktree: {:?}", open_worktree_response); + let worktree = open_worktree_response + .worktree + .ok_or_else(|| anyhow!("empty worktree"))?; + this.update(&mut cx, |workspace, cx| { + let worktree = cx.add_model(|cx| Worktree::remote(worktree, cx)); + cx.observe_model(&worktree, |_, _, cx| cx.notify()); + workspace.worktrees.insert(worktree); + cx.notify(); + }); surf::Result::Ok(()) }); diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index aaccbefe36f5a0b37e4402097e5eb78c6443136c..681075119f1a3a9c6f5111763f30299fec78fce1 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -48,6 +48,7 @@ enum ScanState { pub enum Worktree { Local(LocalWorktree), + Remote(RemoteWorktree), } impl Entity for Worktree { @@ -59,6 +60,10 @@ impl Worktree { Worktree::Local(LocalWorktree::new(path, cx)) } + pub fn remote(worktree: proto::Worktree, cx: &mut ModelContext) -> Self { + Worktree::Remote(RemoteWorktree::new(worktree, cx)) + } + pub fn as_local(&self) -> Option<&LocalWorktree> { if let Worktree::Local(worktree) = self { Some(worktree) @@ -78,6 +83,7 @@ impl Worktree { pub fn snapshot(&self) -> Snapshot { match self { Worktree::Local(worktree) => worktree.snapshot(), + Worktree::Remote(worktree) => worktree.snapshot.clone(), } } @@ -88,6 +94,7 @@ impl Worktree { ) -> impl Future> { match self { Worktree::Local(worktree) => worktree.load_history(path, cx), + Worktree::Remote(worktree) => todo!(), } } @@ -99,6 +106,7 @@ impl Worktree { ) -> impl Future> { match self { Worktree::Local(worktree) => worktree.save(path, content, cx), + Worktree::Remote(worktree) => todo!(), } } } @@ -109,6 +117,7 @@ impl Deref for Worktree { fn deref(&self) -> &Self::Target { match self { Worktree::Local(worktree) => &worktree.snapshot, + Worktree::Remote(worktree) => &worktree.snapshot, } } } @@ -137,7 +146,7 @@ struct FileHandleState { } impl LocalWorktree { - pub fn new(path: impl Into>, cx: &mut ModelContext) -> Self { + fn new(path: impl Into>, cx: &mut ModelContext) -> Self { let abs_path = path.into(); let (scan_state_tx, scan_state_rx) = smol::channel::unbounded(); let id = cx.model_id(); @@ -309,14 +318,22 @@ impl LocalWorktree { cx: &mut ModelContext, ) -> Task> { self.rpc = Some(client.clone()); + let root_name = self.root_name.clone(); let snapshot = self.snapshot(); cx.spawn(|_this, cx| async move { - let paths = cx + let entries = cx .background_executor() .spawn(async move { snapshot - .paths() - .map(|path| path.to_string_lossy().to_string()) + .entries + .cursor::<(), ()>() + .map(|entry| proto::Entry { + is_dir: entry.is_dir(), + path: entry.path.to_string_lossy().to_string(), + inode: entry.inode, + is_symlink: entry.is_symlink, + is_ignored: entry.is_ignored, + }) .collect() }) .await; @@ -325,7 +342,7 @@ impl LocalWorktree { .request( connection_id, proto::ShareWorktree { - worktree: Some(proto::Worktree { paths }), + worktree: Some(proto::Worktree { root_name, entries }), }, ) .await?; @@ -350,6 +367,50 @@ impl fmt::Debug for LocalWorktree { } } +pub struct RemoteWorktree { + snapshot: Snapshot, +} + +impl RemoteWorktree { + fn new(worktree: proto::Worktree, cx: &mut ModelContext) -> Self { + let id = cx.model_id(); + let root_char_bag: CharBag = worktree + .root_name + .chars() + .map(|c| c.to_ascii_lowercase()) + .collect(); + let mut entries = SumTree::new(); + entries.extend( + worktree.entries.into_iter().map(|entry| { + let kind = if entry.is_dir { + EntryKind::Dir + } else { + let mut char_bag = root_char_bag.clone(); + char_bag.extend(entry.path.chars().map(|c| c.to_ascii_lowercase())); + EntryKind::File(char_bag) + }; + Entry { + kind, + path: Path::new(&entry.path).into(), + inode: entry.inode, + is_symlink: entry.is_symlink, + is_ignored: entry.is_ignored, + } + }), + &(), + ); + let snapshot = Snapshot { + id, + scan_id: 0, + abs_path: Path::new("").into(), + root_name: worktree.root_name, + ignores: Default::default(), + entries, + }; + Self { snapshot } + } +} + #[derive(Clone)] pub struct Snapshot { id: usize, @@ -1367,6 +1428,7 @@ impl WorktreeHandle for ModelHandle { } }) } + Worktree::Remote(tree) => todo!(), } }