diff --git a/crates/recent_projects/src/remote_servers.rs b/crates/recent_projects/src/remote_servers.rs index 392ee3048c..30671289ef 100644 --- a/crates/recent_projects/src/remote_servers.rs +++ b/crates/recent_projects/src/remote_servers.rs @@ -32,7 +32,10 @@ use util::ResultExt; use workspace::OpenOptions; use workspace::Toast; use workspace::notifications::NotificationId; -use workspace::{ModalView, Workspace, notifications::DetachAndPromptErr}; +use workspace::{ + ModalView, Workspace, notifications::DetachAndPromptErr, + open_ssh_project_with_existing_connection, +}; use crate::OpenRemote; use crate::ssh_connections::RemoteSettingsContent; @@ -157,13 +160,8 @@ impl ProjectPicker { let app_state = workspace .update(cx, |workspace, _| workspace.app_state().clone()) .ok()?; - let options = cx - .update(|_, cx| (app_state.build_window_options)(None, cx)) - .log_err()?; - - cx.open_window(options, |window, cx| { - window.activate_window(); + cx.update(|_, cx| { let fs = app_state.fs.clone(); update_settings_file::(fs, cx, { let paths = paths @@ -180,32 +178,27 @@ impl ProjectPicker { } } }); - - let tasks = paths - .into_iter() - .map(|path| { - project.update(cx, |project, cx| { - project.find_or_create_worktree(&path, true, cx) - }) - }) - .collect::>(); - window - .spawn(cx, async move |_| { - for task in tasks { - task.await?; - } - Ok(()) - }) - .detach_and_prompt_err("Failed to open path", window, cx, |_, _, _| { - None - }); - - cx.new(|cx| { - telemetry::event!("SSH Project Created"); - Workspace::new(None, project.clone(), app_state.clone(), window, cx) - }) }) .log_err(); + + let options = cx + .update(|_, cx| (app_state.build_window_options)(None, cx)) + .log_err()?; + let window = cx + .open_window(options, |window, cx| { + cx.new(|cx| { + telemetry::event!("SSH Project Created"); + Workspace::new(None, project.clone(), app_state.clone(), window, cx) + }) + }) + .log_err()?; + + open_ssh_project_with_existing_connection( + connection, project, paths, app_state, window, cx, + ) + .await + .log_err(); + this.update(cx, |_, cx| { cx.emit(DismissEvent); }) diff --git a/crates/recent_projects/src/ssh_connections.rs b/crates/recent_projects/src/ssh_connections.rs index 988f5880e0..846aab2985 100644 --- a/crates/recent_projects/src/ssh_connections.rs +++ b/crates/recent_projects/src/ssh_connections.rs @@ -599,7 +599,7 @@ pub async fn open_ssh_project( let did_open_ssh_project = cx .update(|cx| { - workspace::open_ssh_project( + workspace::open_ssh_project_with_new_connection( window, connection_options.clone(), cancel_rx, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 8c0c33808b..843bbd5786 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -6279,7 +6279,7 @@ pub fn create_and_open_local_file( }) } -pub fn open_ssh_project( +pub fn open_ssh_project_with_new_connection( window: WindowHandle, connection_options: SshConnectionOptions, cancel_rx: oneshot::Receiver<()>, @@ -6320,70 +6320,120 @@ pub fn open_ssh_project( ) })?; - let toolchains = DB.toolchains(workspace_id).await?; - for (toolchain, worktree_id, path) in toolchains { - project - .update(cx, |this, cx| { - this.activate_toolchain(ProjectPath { worktree_id, path }, toolchain, cx) - })? - .await; - } - let mut project_paths_to_open = vec![]; - let mut project_path_errors = vec![]; - - for path in paths { - let result = cx - .update(|cx| Workspace::project_path_for_path(project.clone(), &path, true, cx))? - .await; - match result { - Ok((_, project_path)) => { - project_paths_to_open.push((path.clone(), Some(project_path))); - } - Err(error) => { - project_path_errors.push(error); - } - }; - } - - if project_paths_to_open.is_empty() { - return Err(project_path_errors - .pop() - .unwrap_or_else(|| anyhow!("no paths given"))); - } - - cx.update_window(window.into(), |_, window, cx| { - window.replace_root(cx, |window, cx| { - telemetry::event!("SSH Project Opened"); - - let mut workspace = - Workspace::new(Some(workspace_id), project, app_state.clone(), window, cx); - workspace.set_serialized_ssh_project(serialized_ssh_project); - workspace - }); - })?; - - window - .update(cx, |_, window, cx| { - window.activate_window(); - - open_items(serialized_workspace, project_paths_to_open, window, cx) - })? - .await?; - - window.update(cx, |workspace, _, cx| { - for error in project_path_errors { - if error.error_code() == proto::ErrorCode::DevServerProjectPathDoesNotExist { - if let Some(path) = error.error_tag("path") { - workspace.show_error(&anyhow!("'{path}' does not exist"), cx) - } - } else { - workspace.show_error(&error, cx) - } - } - }) + open_ssh_project_inner( + project, + paths, + serialized_ssh_project, + workspace_id, + serialized_workspace, + app_state, + window, + cx, + ) + .await }) } +pub fn open_ssh_project_with_existing_connection( + connection_options: SshConnectionOptions, + project: Entity, + paths: Vec, + app_state: Arc, + window: WindowHandle, + cx: &mut AsyncApp, +) -> Task> { + cx.spawn(async move |cx| { + let (serialized_ssh_project, workspace_id, serialized_workspace) = + serialize_ssh_project(connection_options.clone(), paths.clone(), &cx).await?; + + open_ssh_project_inner( + project, + paths, + serialized_ssh_project, + workspace_id, + serialized_workspace, + app_state, + window, + cx, + ) + .await + }) +} + +async fn open_ssh_project_inner( + project: Entity, + paths: Vec, + serialized_ssh_project: SerializedSshProject, + workspace_id: WorkspaceId, + serialized_workspace: Option, + app_state: Arc, + window: WindowHandle, + cx: &mut AsyncApp, +) -> Result<()> { + let toolchains = DB.toolchains(workspace_id).await?; + for (toolchain, worktree_id, path) in toolchains { + project + .update(cx, |this, cx| { + this.activate_toolchain(ProjectPath { worktree_id, path }, toolchain, cx) + })? + .await; + } + let mut project_paths_to_open = vec![]; + let mut project_path_errors = vec![]; + + for path in paths { + let result = cx + .update(|cx| Workspace::project_path_for_path(project.clone(), &path, true, cx))? + .await; + match result { + Ok((_, project_path)) => { + project_paths_to_open.push((path.clone(), Some(project_path))); + } + Err(error) => { + project_path_errors.push(error); + } + }; + } + + if project_paths_to_open.is_empty() { + return Err(project_path_errors + .pop() + .unwrap_or_else(|| anyhow!("no paths given"))); + } + + cx.update_window(window.into(), |_, window, cx| { + window.replace_root(cx, |window, cx| { + telemetry::event!("SSH Project Opened"); + + let mut workspace = + Workspace::new(Some(workspace_id), project, app_state.clone(), window, cx); + workspace.set_serialized_ssh_project(serialized_ssh_project); + workspace + }); + })?; + + window + .update(cx, |_, window, cx| { + window.activate_window(); + open_items(serialized_workspace, project_paths_to_open, window, cx) + })? + .await?; + + window.update(cx, |workspace, _, cx| { + for error in project_path_errors { + if error.error_code() == proto::ErrorCode::DevServerProjectPathDoesNotExist { + if let Some(path) = error.error_tag("path") { + workspace.show_error(&anyhow!("'{path}' does not exist"), cx) + } + } else { + workspace.show_error(&error, cx) + } + } + })?; + + Ok(()) +} + fn serialize_ssh_project( connection_options: SshConnectionOptions, paths: Vec,