From cf23b0e4a2e34fa33c9f9d3e461d4b7156b078ef Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 14 Apr 2021 16:30:03 +0200 Subject: [PATCH] Prompt for paths asynchronously to avoid double borrow --- Cargo.lock | 1 + gpui/Cargo.toml | 1 + gpui/src/app.rs | 18 +++++++++++- gpui/src/platform/mac/platform.rs | 46 +++++++++++++++++++------------ gpui/src/platform/mod.rs | 6 +++- gpui/src/platform/test.rs | 7 +++-- zed/src/workspace/mod.rs | 26 ++++++++--------- 7 files changed, 70 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35554ea1bd..5692f38a16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,6 +903,7 @@ dependencies = [ "async-std", "async-task", "bindgen", + "block", "cc", "cocoa", "core-foundation", diff --git a/gpui/Cargo.toml b/gpui/Cargo.toml index 5bd32560c6..d87883bab6 100644 --- a/gpui/Cargo.toml +++ b/gpui/Cargo.toml @@ -37,6 +37,7 @@ simplelog = "0.9" [target.'cfg(target_os = "macos")'.dependencies] anyhow = "1" +block = "0.1" cocoa = "0.24" core-foundation = "0.9" core-graphics = "0.22.2" diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 59e4471d07..738ecd79ce 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -5,7 +5,7 @@ use crate::{ platform::{self, WindowOptions}, presenter::Presenter, util::post_inc, - AssetCache, AssetSource, ClipboardItem, FontCache, TextLayoutCache, + AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache, }; use anyhow::{anyhow, Result}; use async_std::sync::Condvar; @@ -570,6 +570,22 @@ impl MutableAppContext { self.platform.set_menus(menus); } + pub fn prompt_for_paths(&self, options: PathPromptOptions, done_fn: F) + where + F: 'static + FnOnce(Option>, &mut MutableAppContext), + { + let app = self.weak_self.as_ref().unwrap().upgrade().unwrap(); + let foreground = self.foreground.clone(); + self.platform().prompt_for_paths( + options, + Box::new(move |paths| { + foreground + .spawn(async move { (done_fn)(paths, &mut *app.borrow_mut()) }) + .detach(); + }), + ); + } + pub fn dispatch_action( &mut self, window_id: usize, diff --git a/gpui/src/platform/mac/platform.rs b/gpui/src/platform/mac/platform.rs index b7ce76f475..e9bf34d684 100644 --- a/gpui/src/platform/mac/platform.rs +++ b/gpui/src/platform/mac/platform.rs @@ -1,5 +1,6 @@ use super::{BoolExt as _, Dispatcher, FontSystem, Window}; use crate::{executor, keymap::Keystroke, platform, ClipboardItem, Event, Menu, MenuItem}; +use block::ConcreteBlock; use cocoa::{ appkit::{ NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, @@ -20,7 +21,7 @@ use objc::{ use ptr::null_mut; use std::{ any::Any, - cell::RefCell, + cell::{Cell, RefCell}, convert::TryInto, ffi::{c_void, CStr}, os::raw::c_char, @@ -267,31 +268,40 @@ impl platform::Platform for MacPlatform { fn prompt_for_paths( &self, options: platform::PathPromptOptions, - ) -> Option> { + done_fn: Box>)>, + ) { unsafe { let panel = NSOpenPanel::openPanel(nil); panel.setCanChooseDirectories_(options.directories.to_objc()); panel.setCanChooseFiles_(options.files.to_objc()); panel.setAllowsMultipleSelection_(options.multiple.to_objc()); panel.setResolvesAliases_(false.to_objc()); - let response = panel.runModal(); - if response == NSModalResponse::NSModalResponseOk { - let mut result = Vec::new(); - let urls = panel.URLs(); - for i in 0..urls.count() { - let url = urls.objectAtIndex(i); - let string = url.absoluteString(); - let string = std::ffi::CStr::from_ptr(string.UTF8String()) - .to_string_lossy() - .to_string(); - if let Some(path) = string.strip_prefix("file://") { - result.push(PathBuf::from(path)); + let done_fn = Cell::new(Some(done_fn)); + let block = ConcreteBlock::new(move |response: NSModalResponse| { + let result = if response == NSModalResponse::NSModalResponseOk { + let mut result = Vec::new(); + let urls = panel.URLs(); + for i in 0..urls.count() { + let url = urls.objectAtIndex(i); + let string = url.absoluteString(); + let string = std::ffi::CStr::from_ptr(string.UTF8String()) + .to_string_lossy() + .to_string(); + if let Some(path) = string.strip_prefix("file://") { + result.push(PathBuf::from(path)); + } } + Some(result) + } else { + None + }; + + if let Some(done_fn) = done_fn.take() { + (done_fn)(result); } - Some(result) - } else { - None - } + }); + let block = block.copy(); + let _: () = msg_send![panel, beginWithCompletionHandler: block]; } } diff --git a/gpui/src/platform/mod.rs b/gpui/src/platform/mod.rs index 5f34396a0e..b98d3a687b 100644 --- a/gpui/src/platform/mod.rs +++ b/gpui/src/platform/mod.rs @@ -40,7 +40,11 @@ pub trait Platform { executor: Rc, ) -> Box; fn key_window_id(&self) -> Option; - fn prompt_for_paths(&self, options: PathPromptOptions) -> Option>; + fn prompt_for_paths( + &self, + options: PathPromptOptions, + done_fn: Box>)>, + ); fn quit(&self); fn write_to_clipboard(&self, item: ClipboardItem); fn read_from_clipboard(&self) -> Option; diff --git a/gpui/src/platform/test.rs b/gpui/src/platform/test.rs index 3baa0dab6e..878449a021 100644 --- a/gpui/src/platform/test.rs +++ b/gpui/src/platform/test.rs @@ -70,8 +70,11 @@ impl super::Platform for Platform { fn quit(&self) {} - fn prompt_for_paths(&self, _: super::PathPromptOptions) -> Option> { - None + fn prompt_for_paths( + &self, + _: super::PathPromptOptions, + _: Box>)>, + ) { } fn write_to_clipboard(&self, item: ClipboardItem) { diff --git a/zed/src/workspace/mod.rs b/zed/src/workspace/mod.rs index d9e9039994..005b4b2435 100644 --- a/zed/src/workspace/mod.rs +++ b/zed/src/workspace/mod.rs @@ -29,19 +29,19 @@ pub struct OpenParams { } fn open(settings: &Receiver, ctx: &mut MutableAppContext) { - if let Some(paths) = ctx.platform().prompt_for_paths(PathPromptOptions { - files: true, - directories: true, - multiple: true, - }) { - ctx.dispatch_global_action( - "workspace:open_paths", - OpenParams { - paths, - settings: settings.clone(), - }, - ); - } + let settings = settings.clone(); + ctx.prompt_for_paths( + PathPromptOptions { + files: true, + directories: true, + multiple: true, + }, + move |paths, ctx| { + if let Some(paths) = paths { + ctx.dispatch_global_action("workspace:open_paths", OpenParams { paths, settings }); + } + }, + ); } fn open_paths(params: &OpenParams, app: &mut MutableAppContext) {