Includes prior-session patches (carry forward so the app compiles): - crates/gpui/build.rs: cross-compile manifest fix - crates/gpui/src/platform.rs: PlatformWindow::activate_with_token trait method - crates/gpui/src/window.rs: Window::activate_with_token public API - crates/gpui_linux/src/linux/wayland/window.rs: WaylandWindow::activate_with_token + activate() keyboard-serial fix Plus the focus-serial fix: - serial.rs: SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; latest_serial_of() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
160 lines
6.2 KiB
Rust
160 lines
6.2 KiB
Rust
use gpui::{App, Context, WeakEntity, Window};
|
|
use notifications::status_toast::StatusToast;
|
|
use std::sync::Arc;
|
|
use ui::{Color, Icon, IconName, IconSize, SharedString};
|
|
use util::ResultExt;
|
|
use workspace::{self, Workspace};
|
|
|
|
pub fn clone_and_open(
|
|
repo_url: SharedString,
|
|
workspace: WeakEntity<Workspace>,
|
|
window: &mut Window,
|
|
cx: &mut App,
|
|
on_success: Arc<
|
|
dyn Fn(&mut Workspace, &mut Window, &mut Context<Workspace>) + Send + Sync + 'static,
|
|
>,
|
|
) {
|
|
let destination_prompt = cx.prompt_for_paths(gpui::PathPromptOptions {
|
|
files: false,
|
|
directories: true,
|
|
multiple: false,
|
|
prompt: Some("Select as Repository Destination".into()),
|
|
});
|
|
|
|
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()
|
|
.map(|name| name.strip_suffix(".git").unwrap_or(name))
|
|
.unwrap_or("repository")
|
|
.to_owned();
|
|
|
|
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(destination_dir.as_path(), &repo_url).await
|
|
})
|
|
})
|
|
.ok()?;
|
|
|
|
if let Err(error) = clone_task.await {
|
|
workspace
|
|
.update(cx, |workspace, cx| {
|
|
let toast = StatusToast::new(error.to_string(), cx, |this, _| {
|
|
this.icon(
|
|
Icon::new(IconName::XCircle)
|
|
.size(IconSize::Small)
|
|
.color(Color::Error),
|
|
)
|
|
.dismiss_button(true)
|
|
});
|
|
workspace.toggle_status_toast(toast, cx);
|
|
})
|
|
.log_err();
|
|
return None;
|
|
}
|
|
|
|
let has_worktrees = workspace
|
|
.read_with(cx, |workspace, cx| {
|
|
workspace.project().read(cx).worktrees(cx).next().is_some()
|
|
})
|
|
.ok()?;
|
|
|
|
let prompt_answer = if has_worktrees {
|
|
cx.update(|window, cx| {
|
|
window.prompt(
|
|
gpui::PromptLevel::Info,
|
|
&format!("Git Clone: {}", repo_name),
|
|
None,
|
|
&["Add repo to project", "Open repo in new project"],
|
|
cx,
|
|
)
|
|
})
|
|
.ok()?
|
|
.await
|
|
.ok()?
|
|
} else {
|
|
// Don't ask if project is empty
|
|
0
|
|
};
|
|
|
|
destination_dir.push(&repo_name);
|
|
|
|
match prompt_answer {
|
|
0 => {
|
|
workspace
|
|
.update_in(cx, |workspace, window, 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 create_task.await.log_err().is_some() {
|
|
workspace_weak
|
|
.update_in(cx, |workspace, window, cx| {
|
|
(on_success)(workspace, window, cx);
|
|
})
|
|
.ok();
|
|
}
|
|
})
|
|
.detach();
|
|
})
|
|
.ok()?;
|
|
}
|
|
1 => {
|
|
workspace
|
|
.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 create_task =
|
|
workspace.project().update(cx, |project, 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 create_task.await.log_err().is_some() {
|
|
workspace_weak
|
|
.update_in(cx, |workspace, window, cx| {
|
|
(on_success)(workspace, window, cx);
|
|
})
|
|
.ok();
|
|
}
|
|
})
|
|
.detach();
|
|
},
|
|
)
|
|
.detach();
|
|
})
|
|
.ok();
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
Some(())
|
|
})
|
|
.detach();
|
|
}
|