diff --git a/Cargo.lock b/Cargo.lock index 05382c74ee..79ce441258 100644 --- a/Cargo.lock +++ b/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", ] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 367db26c8c..be58523140 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -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"] } \ No newline at end of file +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" \ No newline at end of file diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 6620f3d08b..159462fe57 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -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 { - 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 { + 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, IpcReceiver)> { let (server, server_name) = IpcOneShotServer::::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, IpcReceiver