Cargo.lock 🔗
@@ -998,10 +998,12 @@ version = "0.1.0"
dependencies = [
"anyhow",
"clap 3.1.8",
+ "cocoa",
"core-foundation",
"core-services",
"dirs 3.0.1",
"ipc-channel",
+ "objc",
"serde",
]
Max Brunsfeld created
Cargo.lock | 2 ++
crates/cli/Cargo.toml | 10 +++++++---
crates/cli/src/main.rs | 43 ++++++++++++++++++++++++++++++++++---------
3 files changed, 43 insertions(+), 12 deletions(-)
@@ -998,10 +998,12 @@ version = "0.1.0"
dependencies = [
"anyhow",
"clap 3.1.8",
+ "cocoa",
"core-foundation",
"core-services",
"dirs 3.0.1",
"ipc-channel",
+ "objc",
"serde",
]
@@ -13,9 +13,13 @@ path = "src/main.rs"
[dependencies]
anyhow = "1.0"
-core-foundation = "0.9"
-core-services = "0.2"
clap = { version = "3.1", features = ["derive"] }
dirs = "3.0"
ipc-channel = "0.16"
-serde = { version = "1.0", features = ["derive"] }
+serde = { version = "1.0", features = ["derive"] }
+
+[target.'cfg(target_os = "macos")'.dependencies]
+cocoa = "0.24"
+core-foundation = "0.9"
+core-services = "0.2"
+objc = "0.2"
@@ -8,7 +8,8 @@ use core_foundation::{
};
use core_services::{kLSLaunchDefaults, LSLaunchURLSpec, LSOpenFromURLSpec, TCFType};
use ipc_channel::ipc::{IpcOneShotServer, IpcReceiver, IpcSender};
-use std::{fs, path::PathBuf, ptr};
+use objc::{class, msg_send, sel, sel_impl};
+use std::{ffi::CStr, fs, path::PathBuf, ptr};
#[derive(Parser)]
#[clap(name = "zed")]
@@ -48,20 +49,46 @@ fn main() -> Result<()> {
}
fn locate_app() -> Result<PathBuf> {
- Ok(std::env::current_exe()?
- .parent()
- .unwrap()
- .join("bundle/osx/Zed.app"))
+ if cfg!(debug_assertions) {
+ Ok(std::env::current_exe()?
+ .parent()
+ .unwrap()
+ .join("bundle/osx/Zed.app"))
+ } else {
+ Ok(path_to_app_with_bundle_identifier("dev.zed.Zed")
+ .unwrap_or_else(|| "/Applications/Zed.dev".into()))
+ }
+}
+
+fn path_to_app_with_bundle_identifier(bundle_id: &str) -> Option<PathBuf> {
+ use cocoa::{
+ base::{id, nil},
+ foundation::{NSString, NSURL as _},
+ };
+
+ unsafe {
+ let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace];
+ let bundle_id = NSString::alloc(nil).init_str(bundle_id);
+ let app_url: id = msg_send![workspace, URLForApplicationWithBundleIdentifier: bundle_id];
+ if !app_url.is_null() {
+ Some(PathBuf::from(
+ CStr::from_ptr(app_url.path().UTF8String())
+ .to_string_lossy()
+ .to_string(),
+ ))
+ } else {
+ None
+ }
+ }
}
fn launch_app(app_path: PathBuf) -> Result<(IpcSender<CliRequest>, IpcReceiver<CliResponse>)> {
let (server, server_name) = IpcOneShotServer::<IpcHandshake>::new()?;
+ let url = format!("zed-cli://{server_name}");
let status = unsafe {
let app_url =
CFURL::from_path(&app_path, true).ok_or_else(|| anyhow!("invalid app path"))?;
-
- let url = format!("zed-cli://{server_name}");
let url_to_open = CFURL::wrap_under_create_rule(CFURLCreateWithBytes(
ptr::null(),
url.as_ptr(),
@@ -69,9 +96,7 @@ fn launch_app(app_path: PathBuf) -> Result<(IpcSender<CliRequest>, IpcReceiver<C
kCFStringEncodingUTF8,
ptr::null(),
));
-
let urls_to_open = CFArray::from_copyable(&[url_to_open.as_concrete_TypeRef()]);
-
LSOpenFromURLSpec(
&LSLaunchURLSpec {
appURL: app_url.as_concrete_TypeRef(),