mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-02 08:20:09 +00:00
Remove remote worktrees and close their buffers when host unshares
This commit is contained in:
parent
d67227177a
commit
78fbd1307a
3 changed files with 127 additions and 4 deletions
|
@ -968,10 +968,12 @@ mod tests {
|
||||||
editor::{Editor, EditorStyle, Insert},
|
editor::{Editor, EditorStyle, Insert},
|
||||||
fs::{FakeFs, Fs as _},
|
fs::{FakeFs, Fs as _},
|
||||||
language::LanguageRegistry,
|
language::LanguageRegistry,
|
||||||
|
people_panel::JoinWorktree,
|
||||||
rpc::{self, Client, Credentials, EstablishConnectionError},
|
rpc::{self, Client, Credentials, EstablishConnectionError},
|
||||||
settings,
|
settings,
|
||||||
test::FakeHttpClient,
|
test::FakeHttpClient,
|
||||||
user::UserStore,
|
user::UserStore,
|
||||||
|
workspace::Workspace,
|
||||||
worktree::Worktree,
|
worktree::Worktree,
|
||||||
};
|
};
|
||||||
use zrpc::Peer;
|
use zrpc::Peer;
|
||||||
|
@ -1087,6 +1089,94 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_unshare_worktree(mut cx_a: TestAppContext, mut cx_b: TestAppContext) {
|
||||||
|
cx_b.update(zed::workspace::init);
|
||||||
|
let lang_registry = Arc::new(LanguageRegistry::new());
|
||||||
|
|
||||||
|
// Connect to a server as 2 clients.
|
||||||
|
let mut server = TestServer::start().await;
|
||||||
|
let (client_a, _) = server.create_client(&mut cx_a, "user_a").await;
|
||||||
|
let (client_b, user_store_b) = server.create_client(&mut cx_b, "user_b").await;
|
||||||
|
let app_state_b = zed::AppState {
|
||||||
|
rpc: client_b,
|
||||||
|
user_store: user_store_b,
|
||||||
|
..Arc::try_unwrap(cx_b.update(zed::test::test_app_state))
|
||||||
|
.ok()
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
cx_a.foreground().forbid_parking();
|
||||||
|
|
||||||
|
// Share a local worktree as client A
|
||||||
|
let fs = Arc::new(FakeFs::new());
|
||||||
|
fs.insert_tree(
|
||||||
|
"/a",
|
||||||
|
json!({
|
||||||
|
".zed.toml": r#"collaborators = ["user_b"]"#,
|
||||||
|
"a.txt": "a-contents",
|
||||||
|
"b.txt": "b-contents",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let worktree_a = Worktree::open_local(
|
||||||
|
client_a.clone(),
|
||||||
|
"/a".as_ref(),
|
||||||
|
fs,
|
||||||
|
lang_registry.clone(),
|
||||||
|
&mut cx_a.to_async(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
worktree_a
|
||||||
|
.read_with(&cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let remote_worktree_id = worktree_a
|
||||||
|
.update(&mut cx_a, |tree, cx| tree.as_local_mut().unwrap().share(cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let (window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(&app_state_b, cx));
|
||||||
|
cx_b.update(|cx| {
|
||||||
|
cx.dispatch_action(
|
||||||
|
window_b,
|
||||||
|
vec![workspace_b.id()],
|
||||||
|
&JoinWorktree(remote_worktree_id),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
workspace_b
|
||||||
|
.condition(&cx_b, |workspace, _| workspace.worktrees().len() == 1)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let local_worktree_id_b = workspace_b.read_with(&cx_b, |workspace, cx| {
|
||||||
|
let active_pane = workspace.active_pane().read(cx);
|
||||||
|
assert!(active_pane.active_item().is_none());
|
||||||
|
workspace.worktrees().iter().next().unwrap().id()
|
||||||
|
});
|
||||||
|
workspace_b
|
||||||
|
.update(&mut cx_b, |worktree, cx| {
|
||||||
|
worktree.open_entry((local_worktree_id_b, Path::new("a.txt").into()), cx)
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.await;
|
||||||
|
workspace_b.read_with(&cx_b, |workspace, cx| {
|
||||||
|
let active_pane = workspace.active_pane().read(cx);
|
||||||
|
assert!(active_pane.active_item().is_some());
|
||||||
|
});
|
||||||
|
|
||||||
|
worktree_a.update(&mut cx_a, |tree, cx| {
|
||||||
|
tree.as_local_mut().unwrap().unshare(cx);
|
||||||
|
});
|
||||||
|
workspace_b
|
||||||
|
.condition(&cx_b, |workspace, _| workspace.worktrees().len() == 0)
|
||||||
|
.await;
|
||||||
|
workspace_b.read_with(&cx_b, |workspace, cx| {
|
||||||
|
let active_pane = workspace.active_pane().read(cx);
|
||||||
|
assert!(active_pane.active_item().is_none());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_propagate_saves_and_fs_changes_in_shared_worktree(
|
async fn test_propagate_saves_and_fs_changes_in_shared_worktree(
|
||||||
mut cx_a: TestAppContext,
|
mut cx_a: TestAppContext,
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
user,
|
user,
|
||||||
util::TryFutureExt as _,
|
util::TryFutureExt as _,
|
||||||
worktree::{File, Worktree},
|
worktree::{self, File, Worktree},
|
||||||
AppState, Authenticate,
|
AppState, Authenticate,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -886,9 +886,27 @@ impl Workspace {
|
||||||
rpc.authenticate_and_connect(&cx).await?;
|
rpc.authenticate_and_connect(&cx).await?;
|
||||||
let worktree =
|
let worktree =
|
||||||
Worktree::open_remote(rpc.clone(), worktree_id, languages, &mut cx).await?;
|
Worktree::open_remote(rpc.clone(), worktree_id, languages, &mut cx).await?;
|
||||||
this.update(&mut cx, |workspace, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
|
cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
|
||||||
workspace.worktrees.insert(worktree);
|
cx.subscribe(&worktree, move |this, _, event, cx| match event {
|
||||||
|
worktree::Event::Closed => {
|
||||||
|
this.worktrees.retain(|worktree| {
|
||||||
|
worktree.update(cx, |worktree, cx| {
|
||||||
|
if let Some(worktree) = worktree.as_remote_mut() {
|
||||||
|
if worktree.remote_id() == worktree_id {
|
||||||
|
worktree.close_all_buffers(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
this.worktrees.insert(worktree);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,12 @@ pub enum Worktree {
|
||||||
Remote(RemoteWorktree),
|
Remote(RemoteWorktree),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
Closed,
|
||||||
|
}
|
||||||
|
|
||||||
impl Entity for Worktree {
|
impl Entity for Worktree {
|
||||||
type Event = ();
|
type Event = Event;
|
||||||
|
|
||||||
fn release(&mut self, cx: &mut MutableAppContext) {
|
fn release(&mut self, cx: &mut MutableAppContext) {
|
||||||
match self {
|
match self {
|
||||||
|
@ -223,6 +227,7 @@ impl Worktree {
|
||||||
rpc.subscribe_to_entity(remote_id, cx, Self::handle_update),
|
rpc.subscribe_to_entity(remote_id, cx, Self::handle_update),
|
||||||
rpc.subscribe_to_entity(remote_id, cx, Self::handle_update_buffer),
|
rpc.subscribe_to_entity(remote_id, cx, Self::handle_update_buffer),
|
||||||
rpc.subscribe_to_entity(remote_id, cx, Self::handle_buffer_saved),
|
rpc.subscribe_to_entity(remote_id, cx, Self::handle_buffer_saved),
|
||||||
|
rpc.subscribe_to_entity(remote_id, cx, Self::handle_unshare),
|
||||||
];
|
];
|
||||||
|
|
||||||
Worktree::Remote(RemoteWorktree {
|
Worktree::Remote(RemoteWorktree {
|
||||||
|
@ -522,6 +527,16 @@ impl Worktree {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_unshare(
|
||||||
|
&mut self,
|
||||||
|
_: TypedEnvelope<proto::UnshareWorktree>,
|
||||||
|
_: Arc<rpc::Client>,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) -> Result<()> {
|
||||||
|
cx.emit(Event::Closed);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) {
|
fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) {
|
||||||
match self {
|
match self {
|
||||||
Self::Local(worktree) => {
|
Self::Local(worktree) => {
|
||||||
|
|
Loading…
Reference in a new issue