merge integration
This commit is contained in:
commit
5e5ab706b2
|
|
@ -28,3 +28,7 @@ dirs = "6"
|
||||||
arboard = "3"
|
arboard = "3"
|
||||||
zip = "2"
|
zip = "2"
|
||||||
muda = "0.17"
|
muda = "0.17"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
objc2 = "0.6"
|
||||||
|
objc2-foundation = { version = "0.3", features = ["NSAppleEventDescriptor", "NSAppleEventManager", "NSString"] }
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,15 @@ use iced::widget::{
|
||||||
use iced::{Background, Border, Color, Element, Fill, Length, Padding, Shadow, Subscription};
|
use iced::{Background, Border, Color, Element, Fill, Length, Padding, Shadow, Subscription};
|
||||||
use iced::{mouse, keyboard, window, Point, Vector};
|
use iced::{mouse, keyboard, window, Point, Vector};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex, OnceLock};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
static OPEN_QUEUE: OnceLock<Mutex<Vec<PathBuf>>> = OnceLock::new();
|
||||||
|
|
||||||
|
pub fn open_queue() -> &'static Mutex<Vec<PathBuf>> {
|
||||||
|
OPEN_QUEUE.get_or_init(|| Mutex::new(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
use cord_expr::{classify, classify_from, expr_to_sdf, parse_expr, parse_expr_scene, ExprInfo};
|
use cord_expr::{classify, classify_from, expr_to_sdf, parse_expr, parse_expr_scene, ExprInfo};
|
||||||
use crate::highlight::{CordHighlighter, CordHighlighterSettings, format_token};
|
use crate::highlight::{CordHighlighter, CordHighlighterSettings, format_token};
|
||||||
use crate::viewport::SdfViewport;
|
use crate::viewport::SdfViewport;
|
||||||
|
|
@ -333,6 +339,11 @@ impl App {
|
||||||
self.menu_ready = true;
|
self.menu_ready = true;
|
||||||
}
|
}
|
||||||
self.poll_menu_events();
|
self.poll_menu_events();
|
||||||
|
if let Ok(mut q) = open_queue().lock() {
|
||||||
|
for path in q.drain(..) {
|
||||||
|
self.open_path(&path);
|
||||||
|
}
|
||||||
|
}
|
||||||
let new_line = self.source.cursor().position.line;
|
let new_line = self.source.cursor().position.line;
|
||||||
if new_line != self.cursor_line {
|
if new_line != self.cursor_line {
|
||||||
self.cursor_line = new_line;
|
self.cursor_line = new_line;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,133 @@ fn title(app: &App) -> String {
|
||||||
app.title()
|
app.title()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
mod apple_events {
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use objc2::rc::Retained;
|
||||||
|
use objc2::runtime::{AnyObject, NSObject};
|
||||||
|
use objc2::{define_class, msg_send, sel, AnyThread};
|
||||||
|
|
||||||
|
// kCoreEventClass = 'aevt', kAEOpenDocuments = 'odoc', keyDirectObject = '----'
|
||||||
|
const KAEVT: u32 = u32::from_be_bytes(*b"aevt");
|
||||||
|
const KODOC: u32 = u32::from_be_bytes(*b"odoc");
|
||||||
|
const KEY_DIRECT_OBJECT: u32 = u32::from_be_bytes(*b"----");
|
||||||
|
|
||||||
|
define_class!(
|
||||||
|
#[unsafe(super(NSObject))]
|
||||||
|
#[name = "CordOpenHandler"]
|
||||||
|
struct OpenHandler;
|
||||||
|
|
||||||
|
impl OpenHandler {
|
||||||
|
#[unsafe(method(handleOpenEvent:withReplyEvent:))]
|
||||||
|
fn handle_open_event(&self, event: &AnyObject, _reply: &AnyObject) {
|
||||||
|
handle_odoc(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
impl OpenHandler {
|
||||||
|
fn new() -> Retained<Self> {
|
||||||
|
let this = Self::alloc().set_ivars(());
|
||||||
|
unsafe { msg_send![super(this), init] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_odoc(event: &AnyObject) {
|
||||||
|
let file_list: Option<Retained<AnyObject>> = unsafe {
|
||||||
|
msg_send![event, paramDescriptorForKeyword: KEY_DIRECT_OBJECT]
|
||||||
|
};
|
||||||
|
let file_list = match file_list {
|
||||||
|
Some(fl) => fl,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let count: isize = unsafe { msg_send![&*file_list, numberOfItems] };
|
||||||
|
let queue = crate::app::open_queue();
|
||||||
|
|
||||||
|
for i in 1..=count {
|
||||||
|
let desc: Option<Retained<AnyObject>> = unsafe {
|
||||||
|
msg_send![&*file_list, descriptorAtIndex: i]
|
||||||
|
};
|
||||||
|
let desc = match desc {
|
||||||
|
Some(d) => d,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
let url_str: Option<Retained<AnyObject>> = unsafe {
|
||||||
|
msg_send![&*desc, stringValue]
|
||||||
|
};
|
||||||
|
let url_str = match url_str {
|
||||||
|
Some(s) => s,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
let raw: *const std::ffi::c_char = unsafe { msg_send![&*url_str, UTF8String] };
|
||||||
|
if raw.is_null() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let cstr = unsafe { std::ffi::CStr::from_ptr(raw) };
|
||||||
|
let s = match cstr.to_str() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
let path_str = if let Some(stripped) = s.strip_prefix("file://") {
|
||||||
|
percent_decode(stripped)
|
||||||
|
} else {
|
||||||
|
s.to_string()
|
||||||
|
};
|
||||||
|
let path = PathBuf::from(&path_str);
|
||||||
|
if path.exists() {
|
||||||
|
if let Ok(mut q) = queue.lock() {
|
||||||
|
q.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn percent_decode(input: &str) -> String {
|
||||||
|
let mut out = Vec::with_capacity(input.len());
|
||||||
|
let bytes = input.as_bytes();
|
||||||
|
let mut i = 0;
|
||||||
|
while i < bytes.len() {
|
||||||
|
if bytes[i] == b'%' && i + 2 < bytes.len() {
|
||||||
|
if let Ok(byte) = u8::from_str_radix(
|
||||||
|
&input[i + 1..i + 3],
|
||||||
|
16,
|
||||||
|
) {
|
||||||
|
out.push(byte);
|
||||||
|
i += 3;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.push(bytes[i]);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
String::from_utf8(out).unwrap_or_else(|_| input.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_open_handler() {
|
||||||
|
use objc2_foundation::NSAppleEventManager;
|
||||||
|
|
||||||
|
let handler = OpenHandler::new();
|
||||||
|
let mgr = NSAppleEventManager::sharedAppleEventManager();
|
||||||
|
let sel = sel!(handleOpenEvent:withReplyEvent:);
|
||||||
|
unsafe {
|
||||||
|
let _: () = msg_send![
|
||||||
|
&*mgr,
|
||||||
|
setEventHandler: &*handler,
|
||||||
|
andSelector: sel,
|
||||||
|
forEventClass: KAEVT,
|
||||||
|
andEventID: KODOC
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// Leak the handler so it lives for the process lifetime
|
||||||
|
std::mem::forget(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> iced::Result {
|
fn main() -> iced::Result {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
apple_events::register_open_handler();
|
||||||
|
|
||||||
iced::application(App::new, App::update, App::view)
|
iced::application(App::new, App::update, App::view)
|
||||||
.title(title)
|
.title(title)
|
||||||
.theme(theme)
|
.theme(theme)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue