Implement File > Open menu item

This commit is contained in:
Max Brunsfeld 2021-04-08 22:25:54 -07:00
parent f656b387b3
commit 7ebcbdc0cb
7 changed files with 88 additions and 19 deletions

18
Cargo.lock generated
View File

@ -399,8 +399,7 @@ dependencies = [
[[package]] [[package]]
name = "cocoa" name = "cocoa"
version = "0.24.0" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/zed-industries/core-foundation-rs?rev=52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b#52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"
checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"block", "block",
@ -415,8 +414,7 @@ dependencies = [
[[package]] [[package]]
name = "cocoa-foundation" name = "cocoa-foundation"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/zed-industries/core-foundation-rs?rev=52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b#52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"
checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"block", "block",
@ -445,8 +443,7 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.1" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/zed-industries/core-foundation-rs?rev=52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b#52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"
checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -455,14 +452,12 @@ dependencies = [
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.2" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/zed-industries/core-foundation-rs?rev=52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b#52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
[[package]] [[package]]
name = "core-graphics" name = "core-graphics"
version = "0.22.2" version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/zed-industries/core-foundation-rs?rev=52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b#52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"
checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"core-foundation", "core-foundation",
@ -474,8 +469,7 @@ dependencies = [
[[package]] [[package]]
name = "core-graphics-types" name = "core-graphics-types"
version = "0.1.1" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/zed-industries/core-foundation-rs?rev=52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b#52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"core-foundation", "core-foundation",

View File

@ -3,3 +3,9 @@ members = ["zed", "gpui"]
[patch.crates-io] [patch.crates-io]
async-task = {git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e"} async-task = {git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e"}
# TODO - Remove when this is merged: https://github.com/servo/core-foundation-rs/pull/454
cocoa = {git = "https://github.com/zed-industries/core-foundation-rs", rev = "52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"}
cocoa-foundation = {git = "https://github.com/zed-industries/core-foundation-rs", rev = "52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"}
core-foundation = {git = "https://github.com/zed-industries/core-foundation-rs", rev = "52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"}
core-graphics = {git = "https://github.com/zed-industries/core-foundation-rs", rev = "52b7bc0a7026dbbe0da66f5e8de6ce1031476d5b"}

View File

@ -1,9 +1,13 @@
use super::{BoolExt as _, Dispatcher, FontSystem, Window}; use super::{BoolExt as _, Dispatcher, FontSystem, Window};
use crate::{executor, platform}; use crate::{executor, platform};
use anyhow::Result; use anyhow::Result;
use cocoa::{appkit::NSApplication, base::nil}; use cocoa::{
appkit::{NSApplication, NSOpenPanel, NSModalResponse},
base::nil,
foundation::{NSArray, NSString, NSURL},
};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel, sel_impl};
use std::{rc::Rc, sync::Arc}; use std::{path::PathBuf, rc::Rc, sync::Arc};
pub struct App { pub struct App {
dispatcher: Arc<Dispatcher>, dispatcher: Arc<Dispatcher>,
@ -39,6 +43,37 @@ impl platform::App for App {
Ok(Box::new(Window::open(options, executor, self.fonts())?)) Ok(Box::new(Window::open(options, executor, self.fonts())?))
} }
fn prompt_for_paths(
&self,
options: platform::PathPromptOptions,
) -> Option<Vec<std::path::PathBuf>> {
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));
}
}
Some(result)
} else {
None
}
}
}
fn fonts(&self) -> Arc<dyn platform::FontSystem> { fn fonts(&self) -> Arc<dyn platform::FontSystem> {
self.fonts.clone() self.fonts.clone()
} }

View File

@ -41,6 +41,7 @@ pub trait App {
options: WindowOptions, options: WindowOptions,
executor: Rc<executor::Foreground>, executor: Rc<executor::Foreground>,
) -> Result<Box<dyn Window>>; ) -> Result<Box<dyn Window>>;
fn prompt_for_paths(&self, options: PathPromptOptions) -> Option<Vec<PathBuf>>;
fn fonts(&self) -> Arc<dyn FontSystem>; fn fonts(&self) -> Arc<dyn FontSystem>;
fn quit(&self); fn quit(&self);
} }
@ -66,6 +67,12 @@ pub struct WindowOptions<'a> {
pub title: Option<&'a str>, pub title: Option<&'a str>,
} }
pub struct PathPromptOptions {
pub files: bool,
pub directories: bool,
pub multiple: bool,
}
pub trait FontSystem: Send + Sync { pub trait FontSystem: Send + Sync {
fn load_family(&self, name: &str) -> anyhow::Result<Vec<FontId>>; fn load_family(&self, name: &str) -> anyhow::Result<Vec<FontId>>;
fn select_font( fn select_font(

View File

@ -48,6 +48,10 @@ impl super::App for App {
} }
fn quit(&self) {} fn quit(&self) {}
fn prompt_for_paths(&self, _: super::PathPromptOptions) -> Option<Vec<std::path::PathBuf>> {
None
}
} }
impl Window { impl Window {

View File

@ -1,5 +1,5 @@
use fs::OpenOptions; use fs::OpenOptions;
use gpui::platform::{current as platform, Runner as _}; use gpui::platform::{current as platform, PathPromptOptions, Runner as _};
use log::LevelFilter; use log::LevelFilter;
use simplelog::SimpleLogger; use simplelog::SimpleLogger;
use std::{fs, path::PathBuf}; use std::{fs, path::PathBuf};
@ -18,9 +18,24 @@ fn main() {
.set_menus(menus::MENUS) .set_menus(menus::MENUS)
.on_menu_command({ .on_menu_command({
let app = app.clone(); let app = app.clone();
move |command| { let settings_rx = settings_rx.clone();
log::info!("menu command: {}", command); move |command| match command {
app.dispatch_global_action(command, ()) "app:open" => {
if let Some(paths) = app.platform().prompt_for_paths(PathPromptOptions {
files: true,
directories: true,
multiple: true,
}) {
app.dispatch_global_action(
"workspace:open_paths",
OpenParams {
paths,
settings: settings_rx.clone(),
},
);
}
}
_ => app.dispatch_global_action(command, ()),
} }
}) })
.on_finish_launching({ .on_finish_launching({

View File

@ -6,7 +6,7 @@ pub const MENUS: &'static [Menu] = &[
name: "Zed", name: "Zed",
items: &[ items: &[
MenuItem::Action { MenuItem::Action {
name: "About Zed...", name: "About Zed",
keystroke: None, keystroke: None,
action: "app:about-zed", action: "app:about-zed",
}, },
@ -20,6 +20,14 @@ pub const MENUS: &'static [Menu] = &[
}, },
Menu { Menu {
name: "File", name: "File",
items: &[MenuItem::Action {
name: "Open…",
keystroke: Some("cmd-o"),
action: "app:open",
}],
},
Menu {
name: "Edit",
items: &[ items: &[
MenuItem::Action { MenuItem::Action {
name: "Undo", name: "Undo",