Add a command for installing the CLI

This commit is contained in:
Max Brunsfeld 2022-04-19 16:15:00 -07:00 committed by Antonio Scandurra
parent eee1cec3d4
commit fbd1afc51f
4 changed files with 49 additions and 39 deletions

View File

@ -54,8 +54,7 @@ pub trait Platform: Send + Sync {
fn set_cursor_style(&self, style: CursorStyle);
fn local_timezone(&self) -> UtcOffset;
fn path_for_resource(&self, name: Option<&str>, extension: Option<&str>) -> Result<PathBuf>;
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
}
pub(crate) trait ForegroundPlatform {

View File

@ -14,9 +14,7 @@ use cocoa::{
NSPasteboardTypeString, NSSavePanel, NSWindow,
},
base::{id, nil, selector, YES},
foundation::{
NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSString, NSUInteger, NSURL,
},
foundation::{NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSString, NSURL},
};
use core_foundation::{
base::{CFType, CFTypeRef, OSStatus, TCFType as _},
@ -38,8 +36,8 @@ use ptr::null_mut;
use std::{
cell::{Cell, RefCell},
convert::TryInto,
ffi::{c_void, CStr},
os::raw::c_char,
ffi::{c_void, CStr, OsStr},
os::{raw::c_char, unix::ffi::OsStrExt},
path::{Path, PathBuf},
ptr,
rc::Rc,
@ -48,9 +46,6 @@ use std::{
};
use time::UtcOffset;
#[allow(non_upper_case_globals)]
const NSUTF8StringEncoding: NSUInteger = 4;
const MAC_PLATFORM_IVAR: &'static str = "platform";
static mut APP_CLASS: *const Class = ptr::null();
static mut APP_DELEGATE_CLASS: *const Class = ptr::null();
@ -274,10 +269,9 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
for i in 0..urls.count() {
let url = urls.objectAtIndex(i);
if url.isFileURL() == YES {
let path = std::ffi::CStr::from_ptr(url.path().UTF8String())
.to_string_lossy()
.to_string();
result.push(PathBuf::from(path));
if let Ok(path) = ns_url_to_path(url) {
result.push(path)
}
}
}
Some(result)
@ -305,19 +299,13 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
let (done_tx, done_rx) = oneshot::channel();
let done_tx = Cell::new(Some(done_tx));
let block = ConcreteBlock::new(move |response: NSModalResponse| {
let result = if response == NSModalResponse::NSModalResponseOk {
let mut result = None;
if response == NSModalResponse::NSModalResponseOk {
let url = panel.URL();
if url.isFileURL() == YES {
let path = std::ffi::CStr::from_ptr(url.path().UTF8String())
.to_string_lossy()
.to_string();
Some(PathBuf::from(path))
} else {
None
result = ns_url_to_path(panel.URL()).ok()
}
} else {
None
};
}
if let Some(mut done_tx) = done_tx.take() {
let _ = postage::sink::Sink::try_send(&mut done_tx, result);
@ -612,22 +600,18 @@ impl platform::Platform for MacPlatform {
}
}
fn path_for_resource(&self, name: Option<&str>, extension: Option<&str>) -> Result<PathBuf> {
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
unsafe {
let bundle: id = NSBundle::mainBundle();
if bundle.is_null() {
Err(anyhow!("app is not running inside a bundle"))
} else {
let name = name.map_or(nil, |name| ns_string(name));
let extension = extension.map_or(nil, |extension| ns_string(extension));
let path: id = msg_send![bundle, pathForResource: name ofType: extension];
if path.is_null() {
Err(anyhow!("resource could not be found"))
let name = ns_string(name);
let url: id = msg_send![bundle, URLForAuxiliaryExecutable: name];
if url.is_null() {
Err(anyhow!("resource not found"))
} else {
let len = msg_send![path, lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
let bytes = path.UTF8String() as *const u8;
let path = str::from_utf8(slice::from_raw_parts(bytes, len)).unwrap();
Ok(PathBuf::from(path))
ns_url_to_path(url)
}
}
}
@ -717,9 +701,7 @@ extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) {
.into_iter()
.filter_map(|i| {
let path = urls.objectAtIndex(i);
match dbg!(
CStr::from_ptr(path.absoluteString().UTF8String() as *mut c_char).to_str()
) {
match CStr::from_ptr(path.absoluteString().UTF8String() as *mut c_char).to_str() {
Ok(string) => Some(string.to_string()),
Err(err) => {
log::error!("error converting path to string: {}", err);
@ -754,6 +736,20 @@ unsafe fn ns_string(string: &str) -> id {
NSString::alloc(nil).init_str(string).autorelease()
}
unsafe fn ns_url_to_path(url: id) -> Result<PathBuf> {
let path: *mut c_char = msg_send![url, fileSystemRepresentation];
if path.is_null() {
Err(anyhow!(
"url is not a file path: {}",
CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy()
))
} else {
Ok(PathBuf::from(OsStr::from_bytes(
CStr::from_ptr(path).to_bytes(),
)))
}
}
mod security {
#![allow(non_upper_case_globals)]
use super::*;

View File

@ -163,7 +163,7 @@ impl super::Platform for Platform {
UtcOffset::UTC
}
fn path_for_resource(&self, _name: Option<&str>, _extension: Option<&str>) -> Result<PathBuf> {
fn path_for_auxiliary_executable(&self, _name: &str) -> Result<PathBuf> {
Err(anyhow!("app not running inside a bundle"))
}
}

View File

@ -38,7 +38,8 @@ actions!(
DebugElements,
OpenSettings,
IncreaseBufferFontSize,
DecreaseBufferFontSize
DecreaseBufferFontSize,
InstallCommandLineTool,
]
);
@ -66,6 +67,20 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
cx.refresh_windows();
});
});
cx.add_global_action(move |_: &InstallCommandLineTool, cx| {
cx.spawn(|cx| async move {
let path = cx.platform().path_for_auxiliary_executable("cli")?;
let link_path = "/usr/local/bin/zed";
smol::fs::unix::symlink(link_path, path.as_path()).await?;
log::info!(
"created symlink {} -> {}",
link_path,
path.to_string_lossy()
);
Ok::<_, anyhow::Error>(())
})
.detach();
});
cx.add_action({
let app_state = app_state.clone();
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {