mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 21:32:40 +00:00
windows: Refactor prompt_for_paths
and prompt_for_new_path
(#15774)
Refactored `prompt_for_paths` and `prompt_for_new_path`, now errors can propagate properly. Release Notes: - N/A
This commit is contained in:
parent
a2d41b1f89
commit
aec8fb7e37
1 changed files with 60 additions and 106 deletions
|
@ -1,11 +1,6 @@
|
|||
// todo(windows): remove
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
ffi::{c_void, OsString},
|
||||
cell::RefCell,
|
||||
mem::ManuallyDrop,
|
||||
os::windows::ffi::{OsStrExt, OsStringExt},
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
|
@ -288,7 +283,7 @@ impl Platform for WindowsPlatform {
|
|||
}
|
||||
|
||||
// todo(windows)
|
||||
fn activate(&self, ignoring_other_apps: bool) {}
|
||||
fn activate(&self, _ignoring_other_apps: bool) {}
|
||||
|
||||
// todo(windows)
|
||||
fn hide(&self) {
|
||||
|
@ -366,68 +361,9 @@ impl Platform for WindowsPlatform {
|
|||
options: PathPromptOptions,
|
||||
) -> Receiver<Result<Option<Vec<PathBuf>>>> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
self.foreground_executor()
|
||||
.spawn(async move {
|
||||
let tx = Cell::new(Some(tx));
|
||||
|
||||
// create file open dialog
|
||||
let folder_dialog: IFileOpenDialog = unsafe {
|
||||
CoCreateInstance::<std::option::Option<&IUnknown>, IFileOpenDialog>(
|
||||
&FileOpenDialog,
|
||||
None,
|
||||
CLSCTX_ALL,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
// dialog options
|
||||
let mut dialog_options: FILEOPENDIALOGOPTIONS = FOS_FILEMUSTEXIST;
|
||||
if options.multiple {
|
||||
dialog_options |= FOS_ALLOWMULTISELECT;
|
||||
}
|
||||
if options.directories {
|
||||
dialog_options |= FOS_PICKFOLDERS;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
folder_dialog.SetOptions(dialog_options).unwrap();
|
||||
folder_dialog
|
||||
.SetTitle(&HSTRING::from(OsString::from("Select a folder")))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let hr = unsafe { folder_dialog.Show(None) };
|
||||
|
||||
if hr.is_err() {
|
||||
if hr.unwrap_err().code() == HRESULT(0x800704C7u32 as i32) {
|
||||
// user canceled error
|
||||
if let Some(tx) = tx.take() {
|
||||
tx.send(Ok(None)).unwrap();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut results = unsafe { folder_dialog.GetResults().unwrap() };
|
||||
|
||||
let mut paths: Vec<PathBuf> = Vec::new();
|
||||
for i in 0..unsafe { results.GetCount().unwrap() } {
|
||||
let mut item: IShellItem = unsafe { results.GetItemAt(i).unwrap() };
|
||||
let mut path: PWSTR =
|
||||
unsafe { item.GetDisplayName(SIGDN_FILESYSPATH).unwrap() };
|
||||
let mut path_os_string = OsString::from_wide(unsafe { path.as_wide() });
|
||||
|
||||
paths.push(PathBuf::from(path_os_string));
|
||||
}
|
||||
|
||||
if let Some(tx) = tx.take() {
|
||||
if paths.is_empty() {
|
||||
tx.send(Ok(None)).unwrap();
|
||||
} else {
|
||||
tx.send(Ok(Some(paths))).unwrap();
|
||||
}
|
||||
}
|
||||
let _ = tx.send(file_open_dialog(options));
|
||||
})
|
||||
.detach();
|
||||
|
||||
|
@ -439,23 +375,7 @@ impl Platform for WindowsPlatform {
|
|||
let (tx, rx) = oneshot::channel();
|
||||
self.foreground_executor()
|
||||
.spawn(async move {
|
||||
unsafe {
|
||||
let Ok(dialog) = show_savefile_dialog(directory) else {
|
||||
let _ = tx.send(Ok(None));
|
||||
return;
|
||||
};
|
||||
let Ok(_) = dialog.Show(None) else {
|
||||
let _ = tx.send(Ok(None)); // user cancel
|
||||
return;
|
||||
};
|
||||
if let Ok(shell_item) = dialog.GetResult() {
|
||||
if let Ok(file) = shell_item.GetDisplayName(SIGDN_FILESYSPATH) {
|
||||
let _ = tx.send(Ok(Some(PathBuf::from(file.to_string().unwrap()))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
let _ = tx.send(Ok(None));
|
||||
}
|
||||
let _ = tx.send(file_save_dialog(directory));
|
||||
})
|
||||
.detach();
|
||||
|
||||
|
@ -489,8 +409,8 @@ impl Platform for WindowsPlatform {
|
|||
}
|
||||
|
||||
// todo(windows)
|
||||
fn set_menus(&self, menus: Vec<Menu>, keymap: &Keymap) {}
|
||||
fn set_dock_menu(&self, menus: Vec<MenuItem>, keymap: &Keymap) {}
|
||||
fn set_menus(&self, _menus: Vec<Menu>, _keymap: &Keymap) {}
|
||||
fn set_dock_menu(&self, _menus: Vec<MenuItem>, _keymap: &Keymap) {}
|
||||
|
||||
fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>) {
|
||||
self.state.borrow_mut().callbacks.app_menu_action = Some(callback);
|
||||
|
@ -509,7 +429,7 @@ impl Platform for WindowsPlatform {
|
|||
}
|
||||
|
||||
// todo(windows)
|
||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
||||
fn path_for_auxiliary_executable(&self, _name: &str) -> Result<PathBuf> {
|
||||
Err(anyhow!("not yet implemented"))
|
||||
}
|
||||
|
||||
|
@ -589,7 +509,7 @@ impl Platform for WindowsPlatform {
|
|||
)
|
||||
};
|
||||
let password = credential_blob.to_vec();
|
||||
unsafe { CredFree(credentials as *const c_void) };
|
||||
unsafe { CredFree(credentials as *const _ as _) };
|
||||
Ok(Some((username, password)))
|
||||
}
|
||||
})
|
||||
|
@ -655,27 +575,61 @@ fn open_target_in_explorer(target: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn show_savefile_dialog(directory: PathBuf) -> Result<IFileSaveDialog> {
|
||||
let dialog: IFileSaveDialog = CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL)?;
|
||||
let bind_context = CreateBindCtx(0)?;
|
||||
let Ok(full_path) = directory.canonicalize() else {
|
||||
return Ok(dialog);
|
||||
};
|
||||
let dir_str = full_path.into_os_string();
|
||||
if dir_str.is_empty() {
|
||||
return Ok(dialog);
|
||||
fn file_open_dialog(options: PathPromptOptions) -> Result<Option<Vec<PathBuf>>> {
|
||||
let folder_dialog: IFileOpenDialog =
|
||||
unsafe { CoCreateInstance(&FileOpenDialog, None, CLSCTX_ALL)? };
|
||||
|
||||
let mut dialog_options = FOS_FILEMUSTEXIST;
|
||||
if options.multiple {
|
||||
dialog_options |= FOS_ALLOWMULTISELECT;
|
||||
}
|
||||
let dir_vec = dir_str.encode_wide().collect_vec();
|
||||
let ret = SHCreateItemFromParsingName(PCWSTR::from_raw(dir_vec.as_ptr()), &bind_context)
|
||||
.inspect_err(|e| log::error!("unable to create IShellItem: {}", e));
|
||||
if ret.is_ok() {
|
||||
let dir_shell_item: IShellItem = ret.unwrap();
|
||||
let _ = dialog
|
||||
.SetFolder(&dir_shell_item)
|
||||
.inspect_err(|e| log::error!("unable to set folder for save file dialog: {}", e));
|
||||
if options.directories {
|
||||
dialog_options |= FOS_PICKFOLDERS;
|
||||
}
|
||||
|
||||
Ok(dialog)
|
||||
unsafe {
|
||||
folder_dialog.SetOptions(dialog_options)?;
|
||||
if folder_dialog.Show(None).is_err() {
|
||||
// User cancelled
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
let results = unsafe { folder_dialog.GetResults()? };
|
||||
let file_count = unsafe { results.GetCount()? };
|
||||
if file_count == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut paths = Vec::new();
|
||||
for i in 0..file_count {
|
||||
let item = unsafe { results.GetItemAt(i)? };
|
||||
let path = unsafe { item.GetDisplayName(SIGDN_FILESYSPATH)?.to_string()? };
|
||||
paths.push(PathBuf::from(path));
|
||||
}
|
||||
|
||||
Ok(Some(paths))
|
||||
}
|
||||
|
||||
fn file_save_dialog(directory: PathBuf) -> Result<Option<PathBuf>> {
|
||||
let dialog: IFileSaveDialog = unsafe { CoCreateInstance(&FileSaveDialog, None, CLSCTX_ALL)? };
|
||||
if let Some(full_path) = directory.canonicalize().log_err() {
|
||||
let full_path = full_path.to_string_lossy().to_string();
|
||||
if !full_path.is_empty() {
|
||||
let path_item: IShellItem =
|
||||
unsafe { SHCreateItemFromParsingName(&HSTRING::from(&full_path), None)? };
|
||||
unsafe { dialog.SetFolder(&path_item).log_err() };
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
if dialog.Show(None).is_err() {
|
||||
// User cancelled
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
let shell_item = unsafe { dialog.GetResult()? };
|
||||
let file_path_string = unsafe { shell_item.GetDisplayName(SIGDN_FILESYSPATH)?.to_string()? };
|
||||
Ok(Some(PathBuf::from(file_path_string)))
|
||||
}
|
||||
|
||||
fn begin_vsync(vsync_event: HANDLE) {
|
||||
|
|
Loading…
Reference in a new issue