diff --git a/crates/git_ui/src/clone.rs b/crates/git_ui/src/clone.rs index 6b120dad2776ce0a40de9c57749854d06d17263f..f8e65f477930bee451e3323924be90b27e220bb0 100644 --- a/crates/git_ui/src/clone.rs +++ b/crates/git_ui/src/clone.rs @@ -1,82 +1,88 @@ -use gpui::{App, Context, Window}; +use gpui::{App, Context, WeakEntity, Window}; use notifications::status_toast::{StatusToast, ToastIcon}; use std::sync::Arc; use ui::{Color, IconName}; use util::ResultExt; -use workspace::{self, AppState}; +use workspace::{self, Workspace}; pub fn clone_and_open( repo_url: String, - app_state: Arc, + workspace: WeakEntity, + window: &mut Window, cx: &mut App, on_success: Arc< - dyn Fn(&mut workspace::Workspace, &mut Window, &mut Context) - + Send - + Sync - + 'static, + dyn Fn(&mut Workspace, &mut Window, &mut Context) + Send + Sync + 'static, >, ) { - workspace::with_active_or_new_workspace(cx, |_workspace, window, cx| { - let path_prompt = cx.prompt_for_paths(gpui::PathPromptOptions { - files: false, - directories: true, - multiple: false, - prompt: Some("Select directory for cloned repository".into()), - }); + let destination_prompt = cx.prompt_for_paths(gpui::PathPromptOptions { + files: false, + directories: true, + multiple: false, + prompt: Some("Select as Repository Destination".into()), + }); - cx.spawn_in(window, async move |workspace, cx| { - let mut paths = path_prompt.await.ok()?.ok()??; - let mut path = paths.pop()?; + window + .spawn(cx, async move |cx| { + let mut paths = destination_prompt.await.ok()?.ok()??; + let mut destination_dir = paths.pop()?; let repo_name = repo_url .split('/') .next_back() - .and_then(|name| name.strip_suffix(".git")) + .map(|name| name.strip_suffix(".git").unwrap_or(name)) .unwrap_or("repository") .to_owned(); - let fs = workspace - .read_with(cx, |workspace, _| workspace.app_state().fs.clone()) + let clone_task = workspace + .update(cx, |workspace, cx| { + let fs = workspace.app_state().fs.clone(); + let destination_dir = destination_dir.clone(); + let repo_url = repo_url.clone(); + cx.spawn(async move |_workspace, _cx| { + fs.git_clone(&repo_url, destination_dir.as_path()).await + }) + }) .ok()?; - let prompt_answer = match fs.git_clone(&repo_url, path.as_path()).await { - Ok(_) => cx.update(|window, cx| { + if let Err(error) = clone_task.await { + workspace + .update(cx, |workspace, cx| { + let toast = StatusToast::new(error.to_string(), cx, |this, _| { + this.icon(ToastIcon::new(IconName::XCircle).color(Color::Error)) + .dismiss_button(true) + }); + workspace.toggle_status_toast(toast, cx); + }) + .log_err(); + return None; + } + + let prompt_answer = cx + .update(|window, cx| { window.prompt( gpui::PromptLevel::Info, - &format!("Git Clone: \"{}\"", repo_name), + &format!("Git Clone: {}", repo_name), None, - &["Add to current project", "Open in new window"], + &["Add repo to project", "Open repo in new project"], cx, ) - }), - Err(e) => { - workspace - .update(cx, |workspace, cx| { - let toast = StatusToast::new(e.to_string(), cx, |this, _| { - this.icon(ToastIcon::new(IconName::XCircle).color(Color::Error)) - .dismiss_button(true) - }); - workspace.toggle_status_toast(toast, cx); - }) - .ok()?; - - return None; - } - } - .ok()?; + }) + .ok()?; - path.push(&repo_name); + destination_dir.push(&repo_name); match prompt_answer.await.ok()? { 0 => { workspace .update_in(cx, |workspace, window, cx| { - let worktree_task = workspace.project().update(cx, |project, cx| { - project.create_worktree(path.as_path(), true, cx) + let create_task = workspace.project().update(cx, |project, cx| { + project.create_worktree(destination_dir.as_path(), true, cx) }); + let workspace_weak = cx.weak_entity(); + let on_success = on_success.clone(); cx.spawn_in(window, async move |_window, cx| { - if worktree_task.await.log_err().is_some() { + if create_task.await.log_err().is_some() { workspace_weak .update_in(cx, |workspace, window, cx| { (on_success)(workspace, window, cx); @@ -90,20 +96,30 @@ pub fn clone_and_open( } 1 => { workspace - .update(cx, move |_workspace, cx| { + .update(cx, move |workspace, cx| { + let app_state = workspace.app_state().clone(); + let destination_path = destination_dir.clone(); + let on_success = on_success.clone(); + workspace::open_new( Default::default(), app_state, cx, move |workspace, window, cx| { cx.activate(true); - let worktree_task = + + let create_task = workspace.project().update(cx, |project, cx| { - project.create_worktree(&path, true, cx) + project.create_worktree( + destination_path.as_path(), + true, + cx, + ) }); + let workspace_weak = cx.weak_entity(); cx.spawn_in(window, async move |_window, cx| { - if worktree_task.await.log_err().is_some() { + if create_task.await.log_err().is_some() { workspace_weak .update_in(cx, |workspace, window, cx| { (on_success)(workspace, window, cx); @@ -124,5 +140,4 @@ pub fn clone_and_open( Some(()) }) .detach(); - }); } diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 4e94a811510ee07707bf729040d41fc8b1eb922c..d0bb4d2f22e05379c3770180bddad47deebe59ea 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -2848,93 +2848,15 @@ impl GitPanel { } pub(crate) fn git_clone(&mut self, repo: String, window: &mut Window, cx: &mut Context) { - let path = cx.prompt_for_paths(gpui::PathPromptOptions { - files: false, - directories: true, - multiple: false, - prompt: Some("Select as Repository Destination".into()), - }); - let workspace = self.workspace.clone(); - cx.spawn_in(window, async move |this, cx| { - let mut paths = path.await.ok()?.ok()??; - let mut path = paths.pop()?; - let repo_name = repo.split("/").last()?.strip_suffix(".git")?.to_owned(); - - let fs = this.read_with(cx, |this, _| this.fs.clone()).ok()?; - - let prompt_answer = match fs.git_clone(&repo, path.as_path()).await { - Ok(_) => cx.update(|window, cx| { - window.prompt( - PromptLevel::Info, - &format!("Git Clone: {}", repo_name), - None, - &["Add repo to project", "Open repo in new project"], - cx, - ) - }), - Err(e) => { - this.update(cx, |this: &mut GitPanel, cx| { - let toast = StatusToast::new(e.to_string(), cx, |this, _| { - this.icon(ToastIcon::new(IconName::XCircle).color(Color::Error)) - .dismiss_button(true) - }); - - this.workspace - .update(cx, |workspace, cx| { - workspace.toggle_status_toast(toast, cx); - }) - .ok(); - }) - .ok()?; - - return None; - } - } - .ok()?; - - path.push(repo_name); - match prompt_answer.await.ok()? { - 0 => { - workspace - .update(cx, |workspace, cx| { - workspace - .project() - .update(cx, |project, cx| { - project.create_worktree(path.as_path(), true, cx) - }) - .detach(); - }) - .ok(); - } - 1 => { - workspace - .update(cx, move |workspace, cx| { - workspace::open_new( - Default::default(), - workspace.app_state().clone(), - cx, - move |workspace, _, cx| { - cx.activate(true); - workspace - .project() - .update(cx, |project, cx| { - project.create_worktree(&path, true, cx) - }) - .detach(); - }, - ) - .detach(); - }) - .ok(); - } - _ => {} - } - - Some(()) - }) - .detach(); + crate::clone::clone_and_open( + repo, + workspace, + window, + cx, + Arc::new(|_workspace: &mut workspace::Workspace, _window, _cx| {}), + ); } pub(crate) fn git_init(&mut self, window: &mut Window, cx: &mut Context) { diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 9ccbe7c742b494f7c4772d2c411ff284d1ffddf0..b9f368bb09cba81802c8ee2c3d6f0d14bb71fd9e 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -896,15 +896,17 @@ fn handle_open_request(request: OpenRequest, app_state: Arc, cx: &mut .detach_and_log_err(cx); } OpenRequestKind::GitClone { repo_url } => { - let app_state = app_state.clone(); - clone_and_open( - repo_url, - app_state, - cx, - Arc::new(|workspace: &mut workspace::Workspace, window, cx| { - workspace.focus_panel::(window, cx); - }), - ); + workspace::with_active_or_new_workspace(cx, |_workspace, window, cx| { + clone_and_open( + repo_url, + cx.entity().downgrade(), + window, + cx, + Arc::new(|workspace: &mut workspace::Workspace, window, cx| { + workspace.focus_panel::(window, cx); + }), + ); + }); } OpenRequestKind::GitCommit { sha } => { cx.spawn(async move |cx| {