1use gpui::{App, Context, WeakEntity, Window};
2use notifications::status_toast::StatusToast;
3use std::sync::Arc;
4use ui::{Color, Icon, IconName, IconSize, SharedString};
5use util::ResultExt;
6use workspace::{self, Workspace};
7
8pub fn clone_and_open(
9 repo_url: SharedString,
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(
52 Icon::new(IconName::XCircle)
53 .size(IconSize::Small)
54 .color(Color::Error),
55 )
56 .dismiss_button(true)
57 });
58 workspace.toggle_status_toast(toast, cx);
59 })
60 .log_err();
61 return None;
62 }
63
64 let has_worktrees = workspace
65 .read_with(cx, |workspace, cx| {
66 workspace.project().read(cx).worktrees(cx).next().is_some()
67 })
68 .ok()?;
69
70 let prompt_answer = if has_worktrees {
71 cx.update(|window, cx| {
72 window.prompt(
73 gpui::PromptLevel::Info,
74 &format!("Git Clone: {}", repo_name),
75 None,
76 &["Add repo to project", "Open repo in new project"],
77 cx,
78 )
79 })
80 .ok()?
81 .await
82 .ok()?
83 } else {
84 // Don't ask if project is empty
85 0
86 };
87
88 destination_dir.push(&repo_name);
89
90 match prompt_answer {
91 0 => {
92 workspace
93 .update_in(cx, |workspace, window, cx| {
94 let create_task = workspace.project().update(cx, |project, cx| {
95 project.create_worktree(destination_dir.as_path(), true, cx)
96 });
97
98 let workspace_weak = cx.weak_entity();
99 let on_success = on_success.clone();
100 cx.spawn_in(window, async move |_window, cx| {
101 if create_task.await.log_err().is_some() {
102 workspace_weak
103 .update_in(cx, |workspace, window, cx| {
104 (on_success)(workspace, window, cx);
105 })
106 .ok();
107 }
108 })
109 .detach();
110 })
111 .ok()?;
112 }
113 1 => {
114 workspace
115 .update(cx, move |workspace, cx| {
116 let app_state = workspace.app_state().clone();
117 let destination_path = destination_dir.clone();
118 let on_success = on_success.clone();
119
120 workspace::open_new(
121 Default::default(),
122 app_state,
123 cx,
124 move |workspace, window, cx| {
125 cx.activate(true);
126
127 let create_task =
128 workspace.project().update(cx, |project, cx| {
129 project.create_worktree(
130 destination_path.as_path(),
131 true,
132 cx,
133 )
134 });
135
136 let workspace_weak = cx.weak_entity();
137 cx.spawn_in(window, async move |_window, cx| {
138 if create_task.await.log_err().is_some() {
139 workspace_weak
140 .update_in(cx, |workspace, window, cx| {
141 (on_success)(workspace, window, cx);
142 })
143 .ok();
144 }
145 })
146 .detach();
147 },
148 )
149 .detach();
150 })
151 .ok();
152 }
153 _ => {}
154 }
155
156 Some(())
157 })
158 .detach();
159}