mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-26 20:22:30 +00:00
Add a command for installing the CLI
This commit is contained in:
parent
eee1cec3d4
commit
fbd1afc51f
4 changed files with 49 additions and 39 deletions
|
@ -54,8 +54,7 @@ pub trait Platform: Send + Sync {
|
||||||
fn set_cursor_style(&self, style: CursorStyle);
|
fn set_cursor_style(&self, style: CursorStyle);
|
||||||
|
|
||||||
fn local_timezone(&self) -> UtcOffset;
|
fn local_timezone(&self) -> UtcOffset;
|
||||||
|
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
|
||||||
fn path_for_resource(&self, name: Option<&str>, extension: Option<&str>) -> Result<PathBuf>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait ForegroundPlatform {
|
pub(crate) trait ForegroundPlatform {
|
||||||
|
|
|
@ -14,9 +14,7 @@ use cocoa::{
|
||||||
NSPasteboardTypeString, NSSavePanel, NSWindow,
|
NSPasteboardTypeString, NSSavePanel, NSWindow,
|
||||||
},
|
},
|
||||||
base::{id, nil, selector, YES},
|
base::{id, nil, selector, YES},
|
||||||
foundation::{
|
foundation::{NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSString, NSURL},
|
||||||
NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSString, NSUInteger, NSURL,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use core_foundation::{
|
use core_foundation::{
|
||||||
base::{CFType, CFTypeRef, OSStatus, TCFType as _},
|
base::{CFType, CFTypeRef, OSStatus, TCFType as _},
|
||||||
|
@ -38,8 +36,8 @@ use ptr::null_mut;
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
convert::TryInto,
|
convert::TryInto,
|
||||||
ffi::{c_void, CStr},
|
ffi::{c_void, CStr, OsStr},
|
||||||
os::raw::c_char,
|
os::{raw::c_char, unix::ffi::OsStrExt},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
ptr,
|
ptr,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
@ -48,9 +46,6 @@ use std::{
|
||||||
};
|
};
|
||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const NSUTF8StringEncoding: NSUInteger = 4;
|
|
||||||
|
|
||||||
const MAC_PLATFORM_IVAR: &'static str = "platform";
|
const MAC_PLATFORM_IVAR: &'static str = "platform";
|
||||||
static mut APP_CLASS: *const Class = ptr::null();
|
static mut APP_CLASS: *const Class = ptr::null();
|
||||||
static mut APP_DELEGATE_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() {
|
for i in 0..urls.count() {
|
||||||
let url = urls.objectAtIndex(i);
|
let url = urls.objectAtIndex(i);
|
||||||
if url.isFileURL() == YES {
|
if url.isFileURL() == YES {
|
||||||
let path = std::ffi::CStr::from_ptr(url.path().UTF8String())
|
if let Ok(path) = ns_url_to_path(url) {
|
||||||
.to_string_lossy()
|
result.push(path)
|
||||||
.to_string();
|
}
|
||||||
result.push(PathBuf::from(path));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(result)
|
Some(result)
|
||||||
|
@ -305,19 +299,13 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
|
||||||
let (done_tx, done_rx) = oneshot::channel();
|
let (done_tx, done_rx) = oneshot::channel();
|
||||||
let done_tx = Cell::new(Some(done_tx));
|
let done_tx = Cell::new(Some(done_tx));
|
||||||
let block = ConcreteBlock::new(move |response: NSModalResponse| {
|
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();
|
let url = panel.URL();
|
||||||
if url.isFileURL() == YES {
|
if url.isFileURL() == YES {
|
||||||
let path = std::ffi::CStr::from_ptr(url.path().UTF8String())
|
result = ns_url_to_path(panel.URL()).ok()
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
Some(PathBuf::from(path))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(mut done_tx) = done_tx.take() {
|
if let Some(mut done_tx) = done_tx.take() {
|
||||||
let _ = postage::sink::Sink::try_send(&mut done_tx, result);
|
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 {
|
unsafe {
|
||||||
let bundle: id = NSBundle::mainBundle();
|
let bundle: id = NSBundle::mainBundle();
|
||||||
if bundle.is_null() {
|
if bundle.is_null() {
|
||||||
Err(anyhow!("app is not running inside a bundle"))
|
Err(anyhow!("app is not running inside a bundle"))
|
||||||
} else {
|
} else {
|
||||||
let name = name.map_or(nil, |name| ns_string(name));
|
let name = ns_string(name);
|
||||||
let extension = extension.map_or(nil, |extension| ns_string(extension));
|
let url: id = msg_send![bundle, URLForAuxiliaryExecutable: name];
|
||||||
let path: id = msg_send![bundle, pathForResource: name ofType: extension];
|
if url.is_null() {
|
||||||
if path.is_null() {
|
Err(anyhow!("resource not found"))
|
||||||
Err(anyhow!("resource could not be found"))
|
|
||||||
} else {
|
} else {
|
||||||
let len = msg_send![path, lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
|
ns_url_to_path(url)
|
||||||
let bytes = path.UTF8String() as *const u8;
|
|
||||||
let path = str::from_utf8(slice::from_raw_parts(bytes, len)).unwrap();
|
|
||||||
Ok(PathBuf::from(path))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -717,9 +701,7 @@ extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|i| {
|
.filter_map(|i| {
|
||||||
let path = urls.objectAtIndex(i);
|
let path = urls.objectAtIndex(i);
|
||||||
match dbg!(
|
match CStr::from_ptr(path.absoluteString().UTF8String() as *mut c_char).to_str() {
|
||||||
CStr::from_ptr(path.absoluteString().UTF8String() as *mut c_char).to_str()
|
|
||||||
) {
|
|
||||||
Ok(string) => Some(string.to_string()),
|
Ok(string) => Some(string.to_string()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("error converting path to string: {}", 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()
|
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 {
|
mod security {
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -163,7 +163,7 @@ impl super::Platform for Platform {
|
||||||
UtcOffset::UTC
|
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"))
|
Err(anyhow!("app not running inside a bundle"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,8 @@ actions!(
|
||||||
DebugElements,
|
DebugElements,
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
IncreaseBufferFontSize,
|
IncreaseBufferFontSize,
|
||||||
DecreaseBufferFontSize
|
DecreaseBufferFontSize,
|
||||||
|
InstallCommandLineTool,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -66,6 +67,20 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
||||||
cx.refresh_windows();
|
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({
|
cx.add_action({
|
||||||
let app_state = app_state.clone();
|
let app_state = app_state.clone();
|
||||||
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
|
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
|
||||||
|
|
Loading…
Reference in a new issue