From 314b723292f1195d695e923eb8ffff16f1169aa0 Mon Sep 17 00:00:00 2001 From: Bennet Bo Fenner <53836821+bennetbo@users.noreply.github.com> Date: Fri, 26 Apr 2024 21:04:34 +0200 Subject: [PATCH] remote projects: Allow reusing window (#11058) Release Notes: - Allow reusing the window when opening a remote project from the recent projects picker - Fixed an issue, which would not let you rejoin a remote project after disconnecting from it for the first time --------- Co-authored-by: Conrad Co-authored-by: Remco --- crates/collab/src/tests/dev_server_tests.rs | 9 ++++- crates/recent_projects/src/recent_projects.rs | 39 +++++++++++++++---- crates/recent_projects/src/remote_projects.rs | 2 +- crates/semantic_index/src/semantic_index.rs | 27 ++++++++++--- crates/workspace/src/workspace.rs | 26 +++++++++---- 5 files changed, 80 insertions(+), 23 deletions(-) diff --git a/crates/collab/src/tests/dev_server_tests.rs b/crates/collab/src/tests/dev_server_tests.rs index 40ecc66bd7..0917f4994f 100644 --- a/crates/collab/src/tests/dev_server_tests.rs +++ b/crates/collab/src/tests/dev_server_tests.rs @@ -70,6 +70,7 @@ async fn test_dev_server(cx: &mut gpui::TestAppContext, cx2: &mut gpui::TestAppC workspace::join_remote_project( projects[0].project_id.unwrap(), client.app_state.clone(), + None, cx, ) }) @@ -205,7 +206,12 @@ async fn create_remote_project( let projects = store.remote_projects(); assert_eq!(projects.len(), 1); assert_eq!(projects[0].path, "/remote"); - workspace::join_remote_project(projects[0].project_id.unwrap(), client_app_state, cx) + workspace::join_remote_project( + projects[0].project_id.unwrap(), + client_app_state, + None, + cx, + ) }) .await .unwrap(); @@ -301,6 +307,7 @@ async fn test_dev_server_reconnect( workspace::join_remote_project( projects[0].project_id.unwrap(), client2.app_state.clone(), + None, cx, ) }) diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index 6090590b17..813f95e212 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -310,7 +310,6 @@ impl PickerDelegate for RecentProjectsDelegate { workspace.open_workspace_for_paths(false, paths, cx) } } - //TODO support opening remote projects in the same window SerializedWorkspaceLocation::Remote(remote_project) => { let store = ::remote_projects::Store::global(cx).read(cx); let Some(project_id) = store @@ -338,12 +337,38 @@ impl PickerDelegate for RecentProjectsDelegate { }) }; if let Some(app_state) = AppState::global(cx).upgrade() { - let task = - workspace::join_remote_project(project_id, app_state, cx); - cx.spawn(|_, _| async move { - task.await?; - Ok(()) - }) + let handle = if replace_current_window { + cx.window_handle().downcast::() + } else { + None + }; + + if let Some(handle) = handle { + cx.spawn(move |workspace, mut cx| async move { + let continue_replacing = workspace + .update(&mut cx, |workspace, cx| { + workspace. + prepare_to_close(true, cx) + })? + .await?; + if continue_replacing { + workspace + .update(&mut cx, |_workspace, cx| { + workspace::join_remote_project(project_id, app_state, Some(handle), cx) + })? + .await?; + } + Ok(()) + }) + } + else { + let task = + workspace::join_remote_project(project_id, app_state, None, cx); + cx.spawn(|_, _| async move { + task.await?; + Ok(()) + }) + } } else { Task::ready(Err(anyhow::anyhow!("App state not found"))) } diff --git a/crates/recent_projects/src/remote_projects.rs b/crates/recent_projects/src/remote_projects.rs index 8a548c747e..447b22771c 100644 --- a/crates/recent_projects/src/remote_projects.rs +++ b/crates/recent_projects/src/remote_projects.rs @@ -386,7 +386,7 @@ impl RemoteProjects { .on_click(cx.listener(move |_, _, cx| { if let Some(project_id) = project_id { if let Some(app_state) = AppState::global(cx).upgrade() { - workspace::join_remote_project(project_id, app_state, cx) + workspace::join_remote_project(project_id, app_state, None, cx) .detach_and_prompt_err("Could not join project", cx, |_, _| None) } } else { diff --git a/crates/semantic_index/src/semantic_index.rs b/crates/semantic_index/src/semantic_index.rs index c3eccd95f6..097a050ee8 100644 --- a/crates/semantic_index/src/semantic_index.rs +++ b/crates/semantic_index/src/semantic_index.rs @@ -9,8 +9,8 @@ use fs::Fs; use futures::stream::StreamExt; use futures_batch::ChunksTimeoutStreamExt; use gpui::{ - AppContext, AsyncAppContext, Context, EntityId, EventEmitter, Global, Model, ModelContext, - Subscription, Task, WeakModel, + AppContext, AsyncAppContext, BorrowAppContext, Context, Entity, EntityId, EventEmitter, Global, + Model, ModelContext, Subscription, Task, WeakModel, }; use heed::types::{SerdeBincode, Str}; use language::LanguageRegistry; @@ -68,6 +68,18 @@ impl SemanticIndex { project: Model, cx: &mut AppContext, ) -> Model { + let project_weak = project.downgrade(); + project.update(cx, move |_, cx| { + cx.on_release(move |_, cx| { + if cx.has_global::() { + cx.update_global::(|this, _| { + this.project_indices.remove(&project_weak); + }) + } + }) + .detach(); + }); + self.project_indices .entry(project.downgrade()) .or_insert_with(|| { @@ -86,7 +98,7 @@ impl SemanticIndex { pub struct ProjectIndex { db_connection: heed::Env, - project: Model, + project: WeakModel, worktree_indices: HashMap, language_registry: Arc, fs: Arc, @@ -116,7 +128,7 @@ impl ProjectIndex { let fs = project.read(cx).fs().clone(); let mut this = ProjectIndex { db_connection, - project: project.clone(), + project: project.downgrade(), worktree_indices: HashMap::default(), language_registry, fs, @@ -143,8 +155,11 @@ impl ProjectIndex { } fn update_worktree_indices(&mut self, cx: &mut ModelContext) { - let worktrees = self - .project + let Some(project) = self.project.upgrade() else { + return; + }; + + let worktrees = project .read(cx) .visible_worktrees(cx) .filter_map(|worktree| { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 8e29ce22e0..98cddd8d25 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -4785,6 +4785,7 @@ pub fn join_hosted_project( pub fn join_remote_project( project_id: ProjectId, app_state: Arc, + window_to_replace: Option>, cx: &mut AppContext, ) -> Task>> { let windows = cx.windows(); @@ -4816,16 +4817,25 @@ pub fn join_remote_project( ) .await?; - let window_bounds_override = window_bounds_env_override(); - cx.update(|cx| { - let mut options = (app_state.build_window_options)(None, cx); - options.bounds = window_bounds_override; - cx.open_window(options, |cx| { - cx.new_view(|cx| { + if let Some(window_to_replace) = window_to_replace { + cx.update_window(window_to_replace.into(), |_, cx| { + cx.replace_root_view(|cx| { Workspace::new(Default::default(), project, app_state.clone(), cx) + }); + })?; + window_to_replace + } else { + let window_bounds_override = window_bounds_env_override(); + cx.update(|cx| { + let mut options = (app_state.build_window_options)(None, cx); + options.bounds = window_bounds_override; + cx.open_window(options, |cx| { + cx.new_view(|cx| { + Workspace::new(Default::default(), project, app_state.clone(), cx) + }) }) - }) - })? + })? + } }; workspace.update(&mut cx, |_, cx| {