open picker (#14524)
Release Notes: - linux: Added a fallback Open picker for when XDG is not working - Added a new setting `use_system_path_prompts` (default true) that can be disabled to use Zed's builtin keyboard-driven prompts. --------- Co-authored-by: Max <max@zed.dev>
This commit is contained in:
parent
da33aac156
commit
abc5abcd8b
14 changed files with 453 additions and 69 deletions
|
@ -604,6 +604,10 @@ type PromptForNewPath = Box<
|
|||
dyn Fn(&mut Workspace, &mut ViewContext<Workspace>) -> oneshot::Receiver<Option<ProjectPath>>,
|
||||
>;
|
||||
|
||||
type PromptForOpenPath = Box<
|
||||
dyn Fn(&mut Workspace, &mut ViewContext<Workspace>) -> oneshot::Receiver<Option<Vec<PathBuf>>>,
|
||||
>;
|
||||
|
||||
/// Collects everything project-related for a certain window opened.
|
||||
/// In some way, is a counterpart of a window, as the [`WindowHandle`] could be downcast into `Workspace`.
|
||||
///
|
||||
|
@ -646,6 +650,7 @@ pub struct Workspace {
|
|||
centered_layout: bool,
|
||||
bounds_save_task_queued: Option<Task<()>>,
|
||||
on_prompt_for_new_path: Option<PromptForNewPath>,
|
||||
on_prompt_for_open_path: Option<PromptForOpenPath>,
|
||||
render_disconnected_overlay:
|
||||
Option<Box<dyn Fn(&mut Self, &mut ViewContext<Self>) -> AnyElement>>,
|
||||
}
|
||||
|
@ -931,6 +936,7 @@ impl Workspace {
|
|||
centered_layout: false,
|
||||
bounds_save_task_queued: None,
|
||||
on_prompt_for_new_path: None,
|
||||
on_prompt_for_open_path: None,
|
||||
render_disconnected_overlay: None,
|
||||
}
|
||||
}
|
||||
|
@ -1312,6 +1318,10 @@ impl Workspace {
|
|||
self.on_prompt_for_new_path = Some(prompt)
|
||||
}
|
||||
|
||||
pub fn set_prompt_for_open_path(&mut self, prompt: PromptForOpenPath) {
|
||||
self.on_prompt_for_open_path = Some(prompt)
|
||||
}
|
||||
|
||||
pub fn set_render_disconnected_overlay(
|
||||
&mut self,
|
||||
render: impl Fn(&mut Self, &mut ViewContext<Self>) -> AnyElement + 'static,
|
||||
|
@ -1319,11 +1329,60 @@ impl Workspace {
|
|||
self.render_disconnected_overlay = Some(Box::new(render))
|
||||
}
|
||||
|
||||
pub fn prompt_for_open_path(
|
||||
&mut self,
|
||||
path_prompt_options: PathPromptOptions,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
|
||||
if self.project.read(cx).is_remote()
|
||||
|| !WorkspaceSettings::get_global(cx).use_system_path_prompts
|
||||
{
|
||||
let prompt = self.on_prompt_for_open_path.take().unwrap();
|
||||
let rx = prompt(self, cx);
|
||||
self.on_prompt_for_open_path = Some(prompt);
|
||||
rx
|
||||
} else {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let abs_path = cx.prompt_for_paths(path_prompt_options);
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let Ok(result) = abs_path.await else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(result) => {
|
||||
tx.send(result).log_err();
|
||||
}
|
||||
Err(err) => {
|
||||
let rx = this.update(&mut cx, |this, cx| {
|
||||
this.show_portal_error(err.to_string(), cx);
|
||||
let prompt = this.on_prompt_for_open_path.take().unwrap();
|
||||
let rx = prompt(this, cx);
|
||||
this.on_prompt_for_open_path = Some(prompt);
|
||||
rx
|
||||
})?;
|
||||
if let Ok(path) = rx.await {
|
||||
tx.send(path).log_err();
|
||||
}
|
||||
}
|
||||
};
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach();
|
||||
|
||||
rx
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prompt_for_new_path(
|
||||
&mut self,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> oneshot::Receiver<Option<ProjectPath>> {
|
||||
if let Some(prompt) = self.on_prompt_for_new_path.take() {
|
||||
if self.project.read(cx).is_remote()
|
||||
|| !WorkspaceSettings::get_global(cx).use_system_path_prompts
|
||||
{
|
||||
let prompt = self.on_prompt_for_new_path.take().unwrap();
|
||||
let rx = prompt(self, cx);
|
||||
self.on_prompt_for_new_path = Some(prompt);
|
||||
rx
|
||||
|
@ -1339,14 +1398,23 @@ impl Workspace {
|
|||
let (tx, rx) = oneshot::channel();
|
||||
let abs_path = cx.prompt_for_new_path(&start_abs_path);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let abs_path: Option<PathBuf> =
|
||||
Flatten::flatten(abs_path.await.map_err(|e| e.into())).map_err(|err| {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
let abs_path = match abs_path.await? {
|
||||
Ok(path) => path,
|
||||
Err(err) => {
|
||||
let rx = this.update(&mut cx, |this, cx| {
|
||||
this.show_portal_error(err.to_string(), cx);
|
||||
})
|
||||
.ok();
|
||||
err
|
||||
})?;
|
||||
|
||||
let prompt = this.on_prompt_for_new_path.take().unwrap();
|
||||
let rx = prompt(this, cx);
|
||||
this.on_prompt_for_new_path = Some(prompt);
|
||||
rx
|
||||
})?;
|
||||
if let Ok(path) = rx.await {
|
||||
tx.send(path).log_err();
|
||||
}
|
||||
return anyhow::Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let project_path = abs_path.and_then(|abs_path| {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
|
@ -1629,23 +1697,18 @@ impl Workspace {
|
|||
self.client()
|
||||
.telemetry()
|
||||
.report_app_event("open project".to_string());
|
||||
let paths = cx.prompt_for_paths(PathPromptOptions {
|
||||
files: true,
|
||||
directories: true,
|
||||
multiple: true,
|
||||
});
|
||||
let paths = self.prompt_for_open_path(
|
||||
PathPromptOptions {
|
||||
files: true,
|
||||
directories: true,
|
||||
multiple: true,
|
||||
},
|
||||
cx,
|
||||
);
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let paths = match Flatten::flatten(paths.await.map_err(|e| e.into())) {
|
||||
Ok(Some(paths)) => paths,
|
||||
Ok(None) => return,
|
||||
Err(err) => {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.show_portal_error(err.to_string(), cx);
|
||||
})
|
||||
.ok();
|
||||
return;
|
||||
}
|
||||
let Some(paths) = paths.await.log_err().flatten() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(task) = this
|
||||
|
@ -1801,20 +1864,16 @@ impl Workspace {
|
|||
);
|
||||
return;
|
||||
}
|
||||
let paths = cx.prompt_for_paths(PathPromptOptions {
|
||||
files: false,
|
||||
directories: true,
|
||||
multiple: true,
|
||||
});
|
||||
let paths = self.prompt_for_open_path(
|
||||
PathPromptOptions {
|
||||
files: false,
|
||||
directories: true,
|
||||
multiple: true,
|
||||
},
|
||||
cx,
|
||||
);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let paths = Flatten::flatten(paths.await.map_err(|e| e.into())).map_err(|err| {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.show_portal_error(err.to_string(), cx);
|
||||
})
|
||||
.ok();
|
||||
err
|
||||
})?;
|
||||
if let Some(paths) = paths {
|
||||
if let Some(paths) = paths.await.log_err().flatten() {
|
||||
let results = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.open_paths(paths, OpenVisible::All, None, cx)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue