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