1use gpui::{App, Context, WeakEntity, Window};
2use notifications::status_toast::{StatusToast, ToastIcon};
3use std::sync::Arc;
4use ui::{Color, IconName};
5use util::ResultExt;
6use workspace::{self, Workspace};
7
8pub fn clone_and_open(
9 repo_url: String,
10 workspace: WeakEntity<Workspace>,
11 window: &mut Window,
12 cx: &mut App,
13 on_success: Arc<
14 dyn Fn(&mut Workspace, &mut Window, &mut Context<Workspace>) + Send + Sync + 'static,
15 >,
16) {
17 let destination_prompt = cx.prompt_for_paths(gpui::PathPromptOptions {
18 files: false,
19 directories: true,
20 multiple: false,
21 prompt: Some("Select as Repository Destination".into()),
22 });
23
24 window
25 .spawn(cx, async move |cx| {
26 let mut paths = destination_prompt.await.ok()?.ok()??;
27 let mut destination_dir = paths.pop()?;
28
29 let repo_name = repo_url
30 .split('/')
31 .next_back()
32 .map(|name| name.strip_suffix(".git").unwrap_or(name))
33 .unwrap_or("repository")
34 .to_owned();
35
36 let clone_task = workspace
37 .update(cx, |workspace, cx| {
38 let fs = workspace.app_state().fs.clone();
39 let destination_dir = destination_dir.clone();
40 let repo_url = repo_url.clone();
41 cx.spawn(async move |_workspace, _cx| {
42 fs.git_clone(&repo_url, destination_dir.as_path()).await
43 })
44 })
45 .ok()?;
46
47 if let Err(error) = clone_task.await {
48 workspace
49 .update(cx, |workspace, cx| {
50 let toast = StatusToast::new(error.to_string(), cx, |this, _| {
51 this.icon(ToastIcon::new(IconName::XCircle).color(Color::Error))
52 .dismiss_button(true)
53 });
54 workspace.toggle_status_toast(toast, cx);
55 })
56 .log_err();
57 return None;
58 }
59
60 let prompt_answer = cx
61 .update(|window, cx| {
62 window.prompt(
63 gpui::PromptLevel::Info,
64 &format!("Git Clone: {}", repo_name),
65 None,
66 &["Add repo to project", "Open repo in new project"],
67 cx,
68 )
69 })
70 .ok()?;
71
72 destination_dir.push(&repo_name);
73
74 match prompt_answer.await.ok()? {
75 0 => {
76 workspace
77 .update_in(cx, |workspace, window, cx| {
78 let create_task = workspace.project().update(cx, |project, cx| {
79 project.create_worktree(destination_dir.as_path(), true, cx)
80 });
81
82 let workspace_weak = cx.weak_entity();
83 let on_success = on_success.clone();
84 cx.spawn_in(window, async move |_window, cx| {
85 if create_task.await.log_err().is_some() {
86 workspace_weak
87 .update_in(cx, |workspace, window, cx| {
88 (on_success)(workspace, window, cx);
89 })
90 .ok();
91 }
92 })
93 .detach();
94 })
95 .ok()?;
96 }
97 1 => {
98 workspace
99 .update(cx, move |workspace, cx| {
100 let app_state = workspace.app_state().clone();
101 let destination_path = destination_dir.clone();
102 let on_success = on_success.clone();
103
104 workspace::open_new(
105 Default::default(),
106 app_state,
107 cx,
108 move |workspace, window, cx| {
109 cx.activate(true);
110
111 let create_task =
112 workspace.project().update(cx, |project, cx| {
113 project.create_worktree(
114 destination_path.as_path(),
115 true,
116 cx,
117 )
118 });
119
120 let workspace_weak = cx.weak_entity();
121 cx.spawn_in(window, async move |_window, cx| {
122 if create_task.await.log_err().is_some() {
123 workspace_weak
124 .update_in(cx, |workspace, window, cx| {
125 (on_success)(workspace, window, cx);
126 })
127 .ok();
128 }
129 })
130 .detach();
131 },
132 )
133 .detach();
134 })
135 .ok();
136 }
137 _ => {}
138 }
139
140 Some(())
141 })
142 .detach();
143}