clone.rs

  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}